DIRECTORY MathDisplayExpr, MathExpr, MathBox, MathTypes, MathRules, Convert USING [RopeFromAtom], Rope USING [ROPE, Length, Find, Replace, Cat], Imager USING [Context, black, SetColor, MaskRectangle], ImagerColor USING [ColorFromAtom], ImagerBackdoor USING [MakeStipple]; MathDisplayExprImpl: CEDAR PROGRAM IMPORTS MathBox, MathExpr, Imager, ImagerColor, ImagerBackdoor, MathRules, Rope, Convert EXPORTS MathDisplayExpr ~ BEGIN ROPE: TYPE ~ Rope.ROPE; BOX: TYPE ~ MathBox.BOX; EXPR: TYPE ~ MathExpr.EXPR; AtomEXPR: TYPE ~ MathExpr.AtomEXPR; CompoundEXPR: TYPE ~ MathExpr.CompoundEXPR; MatrixEXPR: TYPE ~ MathExpr.MatrixEXPR; Style: TYPE ~ MathTypes.Style; Argument: TYPE ~ MathExpr.Argument; Symbol: TYPE ~ MathExpr.Symbol; AtomClass: TYPE ~ MathExpr.AtomClass; AtomFlavor: TYPE ~ MathExpr.AtomFlavor; CompoundClass: TYPE ~ MathExpr.CompoundClass; AtomValue: TYPE ~ MathTypes.AtomValue; Size: TYPE ~ MathRules.Size; SelectionFlavor: TYPE ~ MathDisplayExpr.SelectionFlavor; Selection: TYPE ~ MathDisplayExpr.Selection; MatrixFlavor: TYPE ~ MathExpr.MatrixFlavor; DisplayExprRep: PUBLIC TYPE ~ RECORD [ tag: ATOM, -- identifying tag such as $integrand expression: DisplayObj, -- atom or compound expr relativeBox: BOX, -- bounding box in relative units absoluteBox: BOX, -- bounding box in absolute units iconic: BOOL _ FALSE, -- TRUE iff expression is currently iconic parent: DisplayExpr _ NIL -- enclosing parent expression ]; DisplayObj: TYPE ~ REF DisplayObjRep; DisplayObjRep: TYPE ~ RECORD [ SELECT type:* FROM atom => [class: AtomClass, value: AtomValue], compound => [class: CompoundClass, subExprs: LIST OF DisplayExpr _ NIL], matrix => [ flavor: MatrixFlavor, -- type of matrix op, e.g. matrix, determinant, etc. nRows, nCols: INT, -- matrix size, rows x cols elements: LIST OF DisplayExpr _ NIL, -- matrix elements openSym: DisplayExpr, -- left bracket closeSym: DisplayExpr, -- right bracket space: DisplayExpr -- inter-element spacing ] ENDCASE ]; AtomDisplayObj: TYPE ~ REF AtomDisplayObjRep; AtomDisplayObjRep: TYPE ~ atom DisplayObjRep; CompoundDisplayObj: TYPE ~ REF CompoundDisplayObjRep; CompoundDisplayObjRep: TYPE ~ compound DisplayObjRep; MatrixDisplayObj: TYPE ~ REF MatrixDisplayObjRep; MatrixDisplayObjRep: TYPE ~ matrix DisplayObjRep; DisplayExpr: TYPE ~ REF DisplayExprRep; -- inside impl module, use rep MakeAtomicDisplayExpr: PUBLIC PROC[tag: ATOM, class: AtomClass, value: AtomValue, relBox, absBox: BOX, parent: DisplayExpr _ NIL] RETURNS[DisplayExpr] ~ { RETURN[NEW[DisplayExprRep _ [tag: tag, relativeBox: relBox, absoluteBox: absBox, parent: parent, expression: NEW[AtomDisplayObjRep _ [atom[class: class, value: value]]]]]]; }; MakeCompoundDisplayExpr: PUBLIC PROC[tag: ATOM, class: CompoundClass, subExprs: LIST OF DisplayExpr, relBox, absBox: BOX, parent: DisplayExpr _ NIL] RETURNS[DisplayExpr] ~ { RETURN[NEW[DisplayExprRep _ [tag: tag, relativeBox: relBox, absoluteBox: absBox, parent: parent, expression: NEW[CompoundDisplayObjRep _ [compound[class: class, subExprs: subExprs]]]]]]; }; MakeMatrixDisplayExpr: PUBLIC PROC[tag: ATOM, flavor: MatrixFlavor, nRows, nCols: INT, elements: LIST OF DisplayExpr, relBox, absBox: BOX, openSym, closeSym, space: DisplayExpr, parent: DisplayExpr _ NIL] RETURNS[DisplayExpr] ~ { RETURN[NEW[DisplayExprRep _ [tag: tag, relativeBox: relBox, absoluteBox: absBox, parent: parent, expression: NEW[MatrixDisplayObjRep _ [matrix[flavor: flavor, nRows: nRows, nCols: nCols, elements: elements, openSym: openSym, closeSym: closeSym, space: space]]]]]]; }; ASRopeFromDisplayExpr: PUBLIC PROC[expr: DisplayExpr] RETURNS[ROPE] ~ { WITH expr.expression SELECT FROM a: AtomDisplayObj => { RETURN[a.class.cvtRope[a.value]]; }; c: CompoundDisplayObj => { valueAS: ROPE _ c.class.cvtAS; -- template for return value argName: ROPE _ NIL; position: INT _ -1; IF Rope.Length[valueAS] < 1 THEN RETURN[""]; FOR l: LIST OF Argument _ c.class.arguments, l.rest UNTIL l = NIL DO argName _ Convert.RopeFromAtom[l.first.name]; position _ Rope.Find[valueAS, argName]; IF position # -1 THEN valueAS _ Rope.Replace[base: valueAS, start: position, len: Rope.Length[argName], with: ASRopeFromDisplayExpr[GetDisplayExpr[l.first.name, c.subExprs]]]; ENDLOOP; RETURN[valueAS]; }; m: MatrixDisplayObj => { Element: TYPE ~ RECORD [ expr: DisplayExpr _ NIL ]; Row: TYPE ~ REF RowRec; RowRec: TYPE ~ RECORD [ elements: SEQUENCE numberOfCols: NAT OF Element ]; Matrix: TYPE ~ REF MatrixRec; MatrixRec: TYPE ~ RECORD[ rows: SEQUENCE numberOfRows: NAT OF Row ]; a: Matrix; currentRow, currentCol: NAT; result: ROPE _ NIL; -- return value a _ NEW[MatrixRec[m.nRows]]; FOR row:INT IN [0..m.nRows) DO a[row] _ NEW[RowRec[m.nCols]]; ENDLOOP; FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO [currentRow, currentCol] _ MathRules.RowColFromAtom[l.first.tag]; a[currentRow - 1][currentCol - 1].expr _ l.first; ENDLOOP; result _ "[ "; -- initialize to matrix start char FOR r:INT IN [0..m.nRows) DO result _ Rope.Cat[result, "[ "]; -- row start char FOR c:INT IN [0..m.nCols) DO result _ Rope.Cat[result, ASRopeFromDisplayExpr[a[r][c].expr]]; IF c # (m.nCols - 1) THEN result _ Rope.Cat[result, ", "]; -- col separator ENDLOOP; result _ Rope.Cat[result, " ]"]; -- row end char IF r # (m.nRows - 1) THEN result _ Rope.Cat[result, ", "]; -- row separator ENDLOOP; result _ Rope.Cat[result, " ]"]; -- end with matrix end char RETURN[result]; }; ENDCASE => ERROR; }; DisplayExprFromExpr: PUBLIC PROC[expr: EXPR] RETURNS[DisplayExpr] ~ { myDisplayExpr, tempDisplayExpr: DisplayExpr; emptyAtom: ATOM _ $expr; -- generic identifier emptyRelBox: BOX _ MathBox.MakeBox[emptyAtom, NIL, other, relative]; emptyAbsBox: BOX _ MathBox.MakeBox[emptyAtom, NIL, other, absolute]; SELECT expr.GetType[] FROM atom => { a: AtomEXPR _ expr.GetAtomExpr[]; RETURN[MakeAtomicDisplayExpr[emptyAtom, MathExpr.GetAtomClass[a], MathExpr.GetValue[a], emptyRelBox, emptyAbsBox]]; }; compound => { c: CompoundEXPR _ expr.GetCompoundExpr[]; compClass: CompoundClass _ MathExpr.GetCompoundClass[c]; displaySubExprs: LIST OF DisplayExpr _ NIL; -- cons up list of display expressions FOR l: LIST OF Argument _ compClass.arguments, l.rest UNTIL l = NIL DO tempDisplayExpr _ DisplayExprFromExpr[MathExpr.GetTaggedExpr[l.first.name, MathExpr.GetSubExprs[c] ! exprNotFound => {ERROR unable[$missingArg]}].expression]; tempDisplayExpr.tag _ l.first.name; -- set name tag for display expr displaySubExprs _ CONS[tempDisplayExpr, displaySubExprs]; ENDLOOP; FOR l: LIST OF Symbol _ compClass.symbols, l.rest UNTIL l = NIL DO tempDisplayExpr _ DisplayExprFromExpr[MathExpr.GetTaggedExpr[l.first.name, MathExpr.GetSubExprs[c] ! exprNotFound => {ERROR unable[$missingSym]}].expression]; tempDisplayExpr.tag _ l.first.name; -- set name tag for display expr displaySubExprs _ CONS[tempDisplayExpr, displaySubExprs]; ENDLOOP; myDisplayExpr _ MakeCompoundDisplayExpr[emptyAtom, MathExpr.GetCompoundClass[c], displaySubExprs, emptyRelBox, emptyAbsBox]; FOR l: LIST OF DisplayExpr _ displaySubExprs, l.rest UNTIL l = NIL DO l.first.parent _ myDisplayExpr; -- set parent ENDLOOP; RETURN[myDisplayExpr]; }; matrix => { m: MatrixEXPR _ expr.GetMatrixExpr[]; elts: LIST OF MathExpr.TaggedMathExpr _ MathExpr.GetMatrixElements[m]; flavor: MatrixFlavor _ MathExpr.GetMatrixFlavor[m]; displayElts: LIST OF DisplayExpr _ NIL; nRows, nCols: NAT; openSym, closeSym, space: DisplayExpr; [nRows, nCols] _ MathExpr.GetMatrixSize[m]; FOR l: LIST OF MathExpr.TaggedMathExpr _ elts, l.rest UNTIL l = NIL DO tempDisplayExpr _ DisplayExprFromExpr[l.first.expression]; tempDisplayExpr.tag _ l.first.id; -- set name tag for display expr displayElts _ CONS[tempDisplayExpr, displayElts]; ENDLOOP; openSym _ DisplayExprFromExpr[MathExpr.GetMatrixOpenSym[m]]; closeSym _ DisplayExprFromExpr[MathExpr.GetMatrixCloseSym[m]]; space _ DisplayExprFromExpr[MathExpr.GetMatrixSpace[m]]; myDisplayExpr _ MakeMatrixDisplayExpr[emptyAtom, flavor, nRows, nCols, displayElts, emptyRelBox, emptyAbsBox, openSym, closeSym, space]; FOR l: LIST OF DisplayExpr _ displayElts, l.rest UNTIL l = NIL DO l.first.parent _ myDisplayExpr; -- set parent ENDLOOP; RETURN[myDisplayExpr]; }; ENDCASE => ERROR; }; ExprFromDisplayExpr: PUBLIC PROC[expr: DisplayExpr] RETURNS[EXPR] ~ { WITH expr.expression SELECT FROM a: AtomDisplayObj => { RETURN[MathExpr.MakeAtomicExpr[a.class.name, a.value]]; }; c: CompoundDisplayObj => { args: LIST OF MathExpr.TaggedMathExpr _ NIL; FOR l: LIST OF DisplayExpr _ c.subExprs, l.rest UNTIL l = NIL DO args _ CONS[[l.first.tag, ExprFromDisplayExpr[l.first]], args]; ENDLOOP; RETURN[MathExpr.MakeCompoundExpr[c.class.name, args]]; }; m: MatrixDisplayObj => { elts: LIST OF MathExpr.TaggedMathExpr; openSym, closeSym, space: EXPR; FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO elts _ CONS[[l.first.tag, ExprFromDisplayExpr[l.first]], elts]; ENDLOOP; openSym _ ExprFromDisplayExpr[m.openSym]; closeSym _ ExprFromDisplayExpr[m.closeSym]; space _ ExprFromDisplayExpr[m.space]; RETURN[MathExpr.MakeMatrixExpr[m.flavor, m.nRows, m.nCols, elts, openSym, closeSym, space]]; }; ENDCASE => ERROR; }; Copy: PUBLIC PROC[expr: DisplayExpr] RETURNS[DisplayExpr] ~ { WITH expr.expression SELECT FROM a: AtomDisplayObj => { RETURN[MakeAtomicDisplayExpr[expr.tag, a.class, a.value, expr.relativeBox, expr.absoluteBox]]; }; c: CompoundDisplayObj => { exprCopy: DisplayExpr; -- return value copiedSubExprs: LIST OF DisplayExpr _ NIL; -- cons up new list of copies FOR l: LIST OF DisplayExpr _ c.subExprs, l.rest UNTIL l = NIL DO copiedSubExprs _ CONS[Copy[l.first], copiedSubExprs]; ENDLOOP; exprCopy _ MakeCompoundDisplayExpr[expr.tag, c.class, copiedSubExprs, expr.relativeBox, expr.absoluteBox]; FOR l: LIST OF DisplayExpr _ copiedSubExprs, l.rest UNTIL l = NIL DO l.first.parent _ exprCopy; -- set parent pointers appropriately ENDLOOP; RETURN[exprCopy]; }; m: MatrixDisplayObj => { exprCopy: DisplayExpr; -- return value copiedElts: LIST OF DisplayExpr _ NIL; -- cons up a new list of copied elements FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO copiedElts _ CONS[Copy[l.first], copiedElts]; ENDLOOP; exprCopy _ MakeMatrixDisplayExpr[expr.tag, m.flavor, m.nRows, m.nCols, copiedElts, expr.relativeBox, expr.absoluteBox, Copy[m.openSym], Copy[m.closeSym], Copy[m.space]]; FOR l: LIST OF DisplayExpr _ copiedElts, l.rest UNTIL l = NIL DO l.first.parent _ exprCopy; -- set parent pointers appropriately ENDLOOP; RETURN[exprCopy]; }; ENDCASE => ERROR; }; Tag: PUBLIC PROC[expr: DisplayExpr] RETURNS[ATOM] ~ { RETURN[expr.tag]; }; Class: PUBLIC PROC[expr: DisplayExpr] RETURNS[ATOM] ~ { WITH expr.expression SELECT FROM a: AtomDisplayObj => RETURN[a.class.name]; c: CompoundDisplayObj => RETURN[c.class.name]; m: MatrixDisplayObj => RETURN[m.flavor.class]; ENDCASE => ERROR; }; GetSubExprs: PUBLIC PROC[expr: DisplayExpr] RETURNS[LIST OF DisplayExpr] ~ { WITH expr.expression SELECT FROM a: AtomDisplayObj => RETURN[NIL]; -- atoms don't have any children c: CompoundDisplayObj => RETURN[c.subExprs]; m: MatrixDisplayObj => RETURN[m.elements]; ENDCASE => ERROR; }; Paint: PUBLIC PROC[expr: DisplayExpr, context: Imager.Context, absBox: BOX, selections: LIST OF Selection] ~ { currentDisplayExpr: DisplayExpr; IF absBox.Type # absolute THEN ERROR unable[$wrongBoxType]; expr.absoluteBox _ absBox; WITH expr.expression SELECT FROM a: AtomDisplayObj => { a.class.paintRule[a.value, a.class.style, context, absBox]; }; c: CompoundDisplayObj => { FOR l: LIST OF Argument _ c.class.arguments, l.rest UNTIL l = NIL DO currentDisplayExpr _ GetDisplayExpr[l.first.name, c.subExprs ! exprNotFound => {ERROR unable[$missingArg]}]; Paint[currentDisplayExpr, context, MathBox.RelToAbsBox[currentDisplayExpr.relativeBox, absBox], selections]; ENDLOOP; FOR l: LIST OF Symbol _ c.class.symbols, l.rest UNTIL l = NIL DO currentDisplayExpr _ GetDisplayExpr[l.first.name, c.subExprs ! exprNotFound => {ERROR unable[$missingArg]}]; Paint[currentDisplayExpr, context, MathBox.RelToAbsBox[currentDisplayExpr.relativeBox, absBox], selections]; ENDLOOP; }; m: MatrixDisplayObj => { FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO Paint[l.first, context, MathBox.RelToAbsBox[l.first.relativeBox, absBox], selections]; ENDLOOP; Paint[m.openSym, context, MathBox.RelToAbsBox[m.openSym.relativeBox, absBox], selections]; Paint[m.closeSym, context, MathBox.RelToAbsBox[m.closeSym.relativeBox, absBox], selections]; }; ENDCASE => ERROR; FOR l: LIST OF Selection _ selections, l.rest UNTIL l = NIL DO IF (expr = l.first.expr) THEN { borderWidth: REAL _ 1; -- pixel borderHeight: REAL _ 1; -- pixel SELECT l.first.flavor FROM copy => context.SetColor[ImagerBackdoor.MakeStipple[8421H, TRUE]]; move => context.SetColor[ImagerBackdoor.MakeStipple[8020H, TRUE]]; kbinput => context.SetColor[ImagerBackdoor.MakeStipple[000F0H, TRUE]]; primary => context.SetColor[ImagerColor.ColorFromAtom[$Invert]]; ENDCASE => ERROR; Imager.MaskRectangle[context, [x: absBox.Offset[].x - (absBox.Extents[].leftExtent + borderWidth), y: absBox.Offset[].y - (absBox.Extents[].descent + borderHeight), w: absBox.Width[] + (2 * borderWidth), h: absBox.Height[] + (2 * borderHeight)]]; context.SetColor[Imager.black]; }; ENDLOOP; }; Format: PUBLIC PROC[expr: DisplayExpr, size: Size] RETURNS[BOX] ~ { subExprBoxes: LIST OF BOX; myBox, tempBox: BOX; WITH expr.expression SELECT FROM a: AtomDisplayObj => { RETURN[MathBox.Scale[MathBox.MakeBox[tag: a.class.name, aliases: NIL, formatClass: a.class.formatClass, type: absolute, extents: a.class.boxRule[a.value, a.class.style]], MathRules.VecFromSize[size]]]; }; c: CompoundDisplayObj => { subExprBoxes _ NIL; -- cons up list of subexpression boxes FOR l: LIST OF Argument _ c.class.arguments, l.rest UNTIL l = NIL DO tempBox _ Format[GetDisplayExpr[l.first.name, c.subExprs ! exprNotFound => {ERROR unable[$missingArg]}], MathRules.ComputeSize[base: size, adjustment: l.first.size]]; subExprBoxes _ CONS[MathBox.MakeBox[l.first.name, l.first.aliases, tempBox.FormatClass[], tempBox.Type[], tempBox.Extents[]], subExprBoxes]; ENDLOOP; FOR l: LIST OF Symbol _ c.class.symbols, l.rest UNTIL l = NIL DO tempBox _ Format[GetDisplayExpr[l.first.name, c.subExprs ! exprNotFound => {ERROR unable[$missingSym]}], MathRules.ComputeSize[base: size, adjustment: l.first.size]]; subExprBoxes _ CONS[MathBox.MakeBox[l.first.name, l.first.aliases, tempBox.FormatClass[], tempBox.Type[], tempBox.Extents[]], subExprBoxes]; ENDLOOP; subExprBoxes _ c.class.boxRule[subExprBoxes]; [myBox, subExprBoxes] _ c.class.compBox[subExprBoxes]; myBox _ MathBox.ChangeFormatClass[myBox, c.class.formatClass]; FOR l: LIST OF DisplayExpr _ c.subExprs, l.rest UNTIL l = NIL DO IF l.first.relativeBox.Type # relative THEN ERROR unable[$wrongBoxType]; l.first.relativeBox _ MathBox.GetBox[l.first.tag, subExprBoxes ! MathBox.boxNotFound => {ERROR unable[$boxNotFound]}]; -- set box ENDLOOP; RETURN[myBox]; }; m: MatrixDisplayObj => { elementBoxes: LIST OF BOX _ NIL; tempBox, spaceBox, openSymBox, closeSymBox: BOX; FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO tempBox _ Format[l.first, MathRules.ComputeSize[base: size, adjustment: script]]; elementBoxes _ CONS[MathBox.MakeBox[l.first.tag, NIL, tempBox.FormatClass[], tempBox.Type[], tempBox.Extents[]], elementBoxes]; ENDLOOP; spaceBox _ Format[m.space, MathRules.ComputeSize[base: size, adjustment: script]]; openSymBox _ Format[m.openSym, normal]; closeSymBox _ Format[m.closeSym, normal]; [myBox, elementBoxes, m.openSym.relativeBox, m.closeSym.relativeBox] _ MathRules.ComposeMatrix[m.nRows, m.nCols, elementBoxes, spaceBox, openSymBox, closeSymBox]; myBox _ MathBox.ChangeFormatClass[myBox, m.flavor.formatClass]; FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO IF l.first.relativeBox.Type # relative THEN ERROR unable[$wrongBoxType]; l.first.relativeBox _ MathBox.GetBox[l.first.tag, elementBoxes ! MathBox.boxNotFound => {ERROR unable[$boxNotFound]}]; -- set box ENDLOOP; RETURN[myBox]; }; ENDCASE => ERROR; }; GetDisplayExpr: PUBLIC PROC[tag: ATOM, exprs: LIST OF DisplayExpr] RETURNS[DisplayExpr] ~ { FOR l: LIST OF DisplayExpr _ exprs, l.rest UNTIL l = NIL DO IF l.first.tag = tag THEN RETURN[l.first]; ENDLOOP; ERROR exprNotFound; }; DisplayExprFromCoords: PUBLIC PROC[expr: DisplayExpr, x, y: REAL] RETURNS[DisplayExpr] ~ { IF expr = NIL THEN ERROR noSelection; IF ~MathBox.Inside[expr.absoluteBox, x, y] THEN ERROR noSelection; WITH expr.expression SELECT FROM a: AtomDisplayObj => { IF Selectable[expr] THEN RETURN[expr] ELSE ERROR noSelection; }; c: CompoundDisplayObj => { FOR l: LIST OF DisplayExpr _ c.subExprs, l.rest UNTIL l = NIL DO IF MathBox.Inside[l.first.absoluteBox, x, y] THEN RETURN[DisplayExprFromCoords[l.first, x, y ! noSelection => CONTINUE]]; ENDLOOP; IF Selectable[expr] THEN RETURN[expr] ELSE ERROR noSelection; }; m: MatrixDisplayObj => { FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO IF MathBox.Inside[l.first.absoluteBox, x, y] THEN RETURN[DisplayExprFromCoords[l.first, x, y ! noSelection => CONTINUE]]; ENDLOOP; IF Selectable[expr] THEN RETURN[expr] ELSE ERROR noSelection; }; ENDCASE => ERROR; }; Selectable: PUBLIC PROC[expr: DisplayExpr] RETURNS[BOOL] ~ { IF expr = NIL THEN RETURN[FALSE]; WITH expr.expression SELECT FROM a: AtomDisplayObj => { IF a.class.flavor = symbol THEN RETURN[FALSE] ELSE RETURN[TRUE]; }; c: CompoundDisplayObj => RETURN[TRUE]; m: MatrixDisplayObj => RETURN[TRUE]; ENDCASE => ERROR; }; SelectableParent: PUBLIC PROC[expr: DisplayExpr] RETURNS[DisplayExpr] ~ { IF (expr = NIL) OR (expr.parent) = NIL THEN ERROR noSelection; RETURN[expr.parent]; }; SelectableChild: PUBLIC PROC[expr: DisplayExpr] RETURNS[DisplayExpr] ~ { childExpr: DisplayExpr _ NIL; IF expr = NIL THEN ERROR noSelection; WITH expr.expression SELECT FROM a: AtomDisplayObj => ERROR noSelection; -- atom has no children c: CompoundDisplayObj => { FOR l: LIST OF Argument _ c.class.arguments, l.rest UNTIL l = NIL DO childExpr _ GetDisplayExpr[l.first.name, c.subExprs]; IF Selectable[childExpr] THEN RETURN[childExpr]; -- return selected expression ENDLOOP; ERROR noSelection; }; m: MatrixDisplayObj => { ERROR noSelection; }; ENDCASE => ERROR; }; SelectableSibling: PUBLIC PROC[expr: DisplayExpr] RETURNS[DisplayExpr] ~ { afterExpr: LIST OF Argument _ NIL; -- sibling after expr in parent's subexpr list siblingExpr: DisplayExpr _ NIL; IF (expr = NIL) OR (expr.parent = NIL) THEN ERROR noSelection; WITH expr.parent.expression SELECT FROM a: AtomDisplayObj => ERROR noSelection; c: CompoundDisplayObj => { FOR l: LIST OF Argument _ c.class.arguments, l.rest UNTIL l = NIL DO IF l.first.name = expr.tag THEN {afterExpr _ l.rest; EXIT}; ENDLOOP; FOR l: LIST OF Argument _ afterExpr, l.rest UNTIL l = NIL DO siblingExpr _ GetDisplayExpr[l.first.name, c.subExprs]; IF Selectable[siblingExpr] THEN RETURN[siblingExpr]; -- return selected expression ENDLOOP; FOR l: LIST OF Argument _ c.class.arguments, l.rest UNTIL l = NIL DO IF l.first.name = expr.tag THEN EXIT; -- already looked thru entire list siblingExpr _ GetDisplayExpr[l.first.name, c.subExprs]; IF Selectable[siblingExpr] THEN RETURN[siblingExpr]; -- return selected expression ENDLOOP; ERROR noSelection; }; m: MatrixDisplayObj => { ERROR noSelection; }; ENDCASE => ERROR; }; Replace: PUBLIC PROC[old: DisplayExpr, new: DisplayExpr] ~ { IF old.parent = NIL THEN ERROR replaceAll; -- complain if no parent new.tag _ old.tag; -- replacement has same tag (e.g. $integrand, etc.) new.parent _ old.parent; -- replacement has same parent as before WITH old.parent.expression SELECT FROM a: AtomDisplayObj => ERROR invalidReplacement; c: CompoundDisplayObj => { newSubExprs: LIST OF DisplayExpr _ NIL; -- build up new list containing new FOR l: LIST OF DisplayExpr _ c.subExprs, l.rest UNTIL l = NIL DO IF l.first.tag = old.tag THEN newSubExprs _ CONS[new, newSubExprs] ELSE newSubExprs _ CONS[l.first, newSubExprs]; ENDLOOP; old.parent.expression _ NEW[CompoundDisplayObjRep _ [compound[class: c.class, subExprs: newSubExprs]]]; }; m: MatrixDisplayObj => { newElements: LIST OF DisplayExpr _ NIL; FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO IF l.first.tag = old.tag THEN newElements _ CONS[new, newElements] ELSE newElements _ CONS[l.first, newElements]; ENDLOOP; old.parent.expression _ NEW[MatrixDisplayObjRep _ [matrix[flavor: m.flavor, nRows: m.nRows, nCols: m.nCols, elements: newElements, openSym: m.openSym, closeSym: m.closeSym, space: m.space]]]; }; ENDCASE => ERROR; }; unable: PUBLIC ERROR[reason: ATOM] = CODE; noSelection: PUBLIC ERROR = CODE; exprNotFound: PUBLIC ERROR = CODE; invalidReplacement: PUBLIC ERROR = CODE; replaceAll: PUBLIC ERROR = CODE; END. dMathDisplayExprImpl.mesa Carl Waldspurger, August 15, 1986 0:10:27 am PDT Type Abbreviations from Imported Types Private Type Rep A DisplayExpr is a MUTABLE math expression which is mapped to a viewer. useful type shorthands Operations on DisplayExpr Display Expression Constructors effects: Constructs and returns a new atomic display expression. effects: Constructs and returns a new compound display expression. effects: Constructs and returns a new matrix display expression. effects: Returns a ROPE in Dennis Arnon's AlgebraStructures format from expr. local declarations recursively copy subexpressions type declarations local variable declarations convert boxes into a SEQUENCE (ugh!) matrix type instantiate matrix "a" (isn't CLU's array[]$create() much nicer, really?) construct rope from matrix in algebrastructures format: add a comma if not last col in row add a comma if not last row in matrix effects: Constructs and returns a new display expression from expr. All Display formatting information is set to default values. local declarations should really combine passed in style with local atomic style recursively generate displayexprs for all subexpressions (arguments & symbols) generate all argument subexpressions generate all symbol subexpressions construct return value now so can set "parent" component of subexpressions set parents of display subexpressions convert elements from expr to displayexpr construct return value now so can set "parent" component of subexpressions effects: Constructs and returns a new EXPR from expr. local declarations recursively build a list of tagged arg exprs local declarations effects: Returns a new, distinct copy of expr. local declarations recursively copy subexpressions construct return value now so we can set parent pointers for subexprs local declarations recursively copy elements construct return value now so we can set parent pointers for subexprs Selectors effects: Returns tag associated with expr. effects: Returns class of expr. effects: Returns subexpressions for expr. Returns NIL if no subexpressions exist Display & Formatting requires: absBox is an absolute BOX modifies: expr effects: Displays expr in context, bounded by absBox. Updates absolute bounding boxes (viewer coords). SIGNALS unable[reason: ATOM] if Painting cannot be completed. local declarations update absolute coordinates paint all subexpressions paint arguments paint symbols paint all matrix elements paint open & close symbols if selected, highlight region appropriately set proper color depending on selectiion flavor highlight region reset color to black modifies: expr effects: expr is updated into a "paintable" form. Returns a bounding box for expr. SIGNALS unable[reason: ATOM] if Formatting can not be completed. local declarations recursively format all subexpressions (arguments & symbols) format all argument subexpressions format all symbol subexpressions compute corrected boxes using sizing constraints compose layout for boxes using alignment constraints set format class for mybox set relative boxes of display subexpressions local declarations recursively format all matrix elements format openSym, closeSym, and space compose layout for matrix by using alignment constraints set format class for mybox set relative boxes of matrix elements List Operations effects: Returns the DisplayExpr in exprs associated with tag. SIGNALS exprNotFound if no association exists. cdr down list looking for tag not found, so signal error Selection Operations effects: Returns the subexpression associated with coordinates [x, y] in expression expr. SIGNALS noSelection if no association exists. see if selection can be further narrowed if above loop does not return, then can't narrow selection any more see if selection can be further narrowed if above loop does not return, then can't narrow selection any more effects: Returns TRUE iff expr is selectable. effects: Returns the parent (enclosing expression) of expr. SIGNALS noParent if no selectable parent exists. complain if no expr or no parent effects: Returns a child expressions (subexpression) for expr. SIGNALS noSelection if no selectable child exists. local declarations keep looking for selectable child if there are no selectable children, signal noSelection ** FOO FIX THIS ** effects: Returns the "next" sibling expression from expr. SIGNALS noSelection if no selectable sibling exists. local declarations "cycle" thru parent's children and return "next" selectable sibling in list find starting point to begin looking for next selectable sibling expr look for next selectable sibling in exprs after expr in list (i.e. in afterExpr) if no selectable sibling exists after expr, then wraparound list to before expr if we haven't RETURNed yet, then there are no selectable siblings ** FOO FIX THIS ** expects: old is a subexpression enclosed by some expresion, call it PARENT[old] modifies: PARENT[old] effects: Substitutes new for old as a subexpression of PARENT[old]. Sets TAG[new] = TAG[old] SIGNALS replaceAll if PARENT[old] does not exist. caveats: Enclosing expression must be reformatted before Paint[]'ing impossible case since atoms have no children mutate subexpression list (in PARENT[old]) mutate subexpression list (in PARENT[old]) Signals & Errors ΚZ˜Jšœ™Jšœ0™0J˜šΟk ˜ J˜J˜ J˜J˜ Jšœ ˜ Jšœœ˜Jšœœœ˜.Jšœœ+˜7Icodešœ œ˜"Kšœœ˜#—J˜šΟnœœ˜"JšœQ˜XJšœ˜J˜Jš˜J˜šž&™&J™Jšœœœ˜Jšœœ œ˜Jšœœ œ˜Jšœ œ˜#Jšœœ˜+Jšœ œ˜'Jšœœ˜Jšœ œ˜#Jšœœ˜Jšœ œ˜%Jšœ œ˜'Jšœœ˜-Jšœ œ˜&Jšœœ˜Jšœœ#˜8Jšœ œ˜,Jšœœ˜+J˜J˜—Jšž™™JšœG™GK˜šœœœ˜šœ˜KšœœΟc%˜1KšœŸ˜1Kšœ œŸ!˜4Kšœ œŸ!˜4KšœœœŸ*˜AKšœœŸ˜9K˜—K˜—Kšœ œœ˜'šœœœ˜šœ˜K˜-Kšœ-œœœ˜Hšœ ˜ KšœŸ4˜KKšœœŸ˜/Kšœ œœœŸ˜8KšœŸ˜%KšœŸ˜'KšœŸ˜+Kšœ˜—Kš˜—K˜K˜—Kšœ™Kšœœœ˜-Kšœœ˜-Kšœœœ˜5Kšœœ˜5Kšœœœ˜1Kšœœ˜1K˜K˜Kšœ œœŸ˜GK˜K˜J™—šž™J™Jšž™K™šžœœœœ6œœœ˜›KšœA™AKšœœcœ<˜¬K˜K˜—šžœœœœ"œœœœœ˜­KšœC™CKšœœcœJ˜ΊK˜—K˜šžœœœœ&œ œœœ?œœ˜ζKšœA™AKšœœcœ˜˜ˆK˜—K˜š žœœœœœ˜GKšœC™CKšœ™K™šœœ˜ K˜šœ˜Kšœ˜!K˜—K˜K˜˜Kšœ™Kšœ œŸ˜˜8K˜—KšœJ™JK˜ˆK˜š œœœ#œœ˜AKšœ Ÿ ˜-Kšœ˜—K˜Kšœ˜K˜—K˜Kšœœ˜—K™K˜—K˜š žœœœœœ˜EKšœ6™6K™šœœ˜ K˜˜Kšœ1˜7K˜—K˜˜Kšœ™Kšœœœœ˜,K˜Kšœ,™,š œœœ"œœ˜@Kšœœ4˜?Kšœ˜—K˜Kšœ0˜6K˜—K˜˜Kšœ™Kšœœœ˜&Kšœœ˜K˜š œœœ"œœ˜@Kšœœ4˜?Kšœ˜—K˜K˜)K˜+K˜%K˜KšœV˜\K˜—K˜Kšœœ˜—˜K˜—K˜—K˜šžœœœœ˜=Kšœ/™/K™šœœ˜ K˜šœ˜KšœX˜^K˜—K˜K˜˜Kšœ™KšœŸ˜'KšœœœœŸ˜IK˜Kšœ™š œœœ"œœ˜@Kšœœ ˜5Kšœ˜ K˜—KšœE™EKšœj˜jš œœœ&œœ˜DKšœŸ$˜@Kšœ˜—K˜Kšœ ˜K˜—K˜˜K˜Kšœ™KšœŸ˜&Kšœ œœœŸ(˜PK˜Kšœ™š œœœ"œœ˜@Kšœ œ˜-Kšœ˜—K˜KšœE™EKšœ©˜©š œœœ"œœ˜@KšœŸ$˜@Kšœ˜—K˜Kšœ ˜K˜K™K˜—Kšœœ˜—K˜K˜—K˜Kšž ™ K™š žœœœœœ˜5Kšœ+™+Kšœ ˜K˜—K˜šžœ œœœ˜7Kšœ ™ šœœ˜ Kšœœ˜*Kšœœ˜.Kšœœ˜.Kšœœ˜—K˜—K™K˜š ž œœœœœœ˜LKšœ*™*Kšœ0™0K™šœœ˜ KšœœœŸ ˜CKšœœ ˜,Kšœœ ˜*Kšœœ˜—K˜—K˜K˜Kšž™—˜š žœœœ5œœœ˜oKšœ#™#Kšœ™Kšœ6™6Kšœ:™:KšœG™GK™Kšœ™K˜ K™Kšœ™Kšœœœ˜;K˜K˜šœœ˜ K˜˜K˜;K˜—K˜˜K˜Kšœ™K™Kšœ™š œœœ&œœ˜DKšœPœ˜lKšœl˜lKšœ˜K˜—Kšœ ™ š œœœ"œœ˜@KšœPœ˜lKšœl˜lKšœ˜—K˜—K˜K˜˜Kšœ™š œœœ"œœ˜@KšœV˜VKšœ˜K˜—Kšœ™KšœZ˜ZKšœ\˜\K˜—K˜Kšœœ˜K˜—Kšœ+™+š œœœ œœ˜>šœœ˜Kšœ œŸ˜ KšœœŸ˜!K˜Kšœ/™/šœ˜Kšœ;œ˜BKšœ;œ˜BKšœ?œ˜FKšœ@˜@Kšœœ˜K˜—Kšœ™K˜φK˜Kšœ™K˜K˜—Kšœ˜—K˜K˜—K˜š žœœœ œœ˜CKšœ™Kšœ2™2Kšœ*™*KšœJ™JK™Kšœ™Kšœœœœ˜Kšœœ˜K˜šœœ˜ K˜šœ˜Kšœ;œ…˜ΙK˜K˜—K˜šœ˜K˜Kšœ;™;K˜KšœœŸ&˜;K˜Kšœ"™"š œœœ&œœ˜DKšœLœU˜¦Kšœœy˜ŒKšœ˜—K˜Kšœ ™ š œœœ"œœ˜@KšœLœU˜¦Kšœœy˜ŒKšœ˜—K˜Kšœ0™0K˜-K˜Kšœ4™4K˜6Kšœ™K˜>K˜Kšœ,™,š œœœ"œœ˜@Kšœ%œœ˜HKšœYœŸ ˜‚Kšœ˜—K˜Kšœ˜K˜—K˜˜Kšœ™Kš œœœœœ˜ Kšœ,œ˜0K˜Kšœ&™&š œœœ"œœ˜@KšœQ˜QKšœœœK˜Kšœ˜—K˜Kšœ#™#K˜RK˜'K˜)K˜Kšœ8™8K˜’Kšœ™K˜?K˜Kšœ%™%š œœœ"œœ˜@Kšœ%œœ˜HKšœYœŸ ˜‚Kšœ˜—K˜Kšœ˜K˜K˜—K˜Kšœœ˜—K™K˜—K˜K˜Kšž™K™šžœœœœ œœœ˜[Kšœ>™>Kšœ7™7K˜Kšœ™š œœœœœ˜;Kšœœœ ˜*Kšœ˜—K˜Kšœ™Kšœ˜K˜——K™™K˜Kšž™K™š žœœœœœ˜ZKšœ\™\K™7K™Kšœœœœ ˜%Kšœ)œœ ˜BK˜šœœ˜ K˜šœ˜Kš œœœœœ ˜=K˜K˜—˜Kšœ(™(š œœœ"œœ˜@šœ+˜1Kšœ6œ˜G—Kšœ˜—K˜KšœC™CKš œœœœœ˜?K˜—K˜˜Kšœ(™(š œœœ"œœ˜@šœ+˜1Kšœ6œ˜G—Kšœ˜—K˜KšœC™CKš œœœœœ˜?K˜—K˜Kšœœ˜—K˜K˜˜K˜——š ž œœœœœ˜™>K™Kšœ™Kšœ œœ œŸ.˜RKšœœ˜K˜Kš œ œœœœœ ˜>K˜KšœK™Kšœœ˜'Kšœœ ˜'˜Kšœ) œ™Eš œœœ&œœ˜DKšœœœ˜;Kšœ˜—Kšœ* œ!™Pš œœœœœ˜