MathBoxTreesImpl.mesa
Copyright Ó 1989 by Xerox Corporation. All rights reserved.
Arnon, September 7, 1989 10:21:56 am PDT
DIRECTORY
MathBoxTree,
MathExpr,
MathBox,
MathConstructors,
MathDB,
MathTypes,
MathRules,
Convert USING [RopeFromAtom],
Rope USING [ROPE, Length, Find, Replace, Cat],
Imager USING [Context, DoSaveAll, MaskRectangle, MaskStrokeTrajectory, SetColor, SetStrokeWidth],
ImagerBackdoor USING [invert],
ImagerFont USING [Extents, Find, Font, RopeBoundingBox, Scale],
ImagerPath USING [LineToX, LineToY, MoveTo],
Vector2 USING [InlineAdd],
XRope;
MathBoxTreesImpl: CEDAR PROGRAM
IMPORTS MathBox, MathExpr, MathDB, MathConstructors, Imager, ImagerBackdoor, ImagerFont, ImagerPath, MathRules, Rope, Convert, Vector2, XRope
EXPORTS MathBoxTree ~
BEGIN
Type Abbreviations from Imported Interfaces
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;
MatrixClass: TYPE ~ MathExpr.MatrixClass;
Size: TYPE ~ MathRules.Size;
Selection: TYPE ~ MathBoxTree.Selection;
ReplacePair: TYPE ~ MathBoxTree.ReplacePair;
Private Type Rep
BoxTreeDataRep: TYPE ~ RECORD [
SELECT type:* FROM
privateTree => [
Display subtree of a atomicObject; "private" since just Boxes, no Objects.
No subtree is selectable (only Objects are selectable)
root: Box, -- cannot be NIL since visibility/non-visibility is a property of Objects (i.e. only of ancestors of privateTrees)
parent: BoxTreeData, -- cannot be NIL since (root of) a privateTree is always a child either of some privateTree, or of some atomicObject.
children: LIST OF BoxTreeData ← NIL -- All children of a privateTree are privateTrees.
Leaf Box iff children = NIL
],
atomicObject => [
I.e. a "packed Object", i.e. no subcomponent selectable
root: Box ← NIL, -- object visible iff root # NIL
parent: BoxTreeData ← NIL, -- root is an absolute Box iff parent = NIL (otherwise relative)
children: LIST OF BoxTreeData ← NIL -- All children of a atomicObject are privateTrees.
root is a leaf Box iff children = NIL
object: Object,
],
This Object (self.object) selectable iff visible
Nothing inside self.root, e.g. no subBoxTree or subObject, is selectable
self.root and self.children created by the EltDisplay proc of (the domain) self.object.class, with either no "unpacking" possible (e.g. ground domain), or a passed-in environment specifying "no unpacking".
compositeObject => [
"Unpacked" (to at least one level) Object display
root: Box ← NIL, -- bounding, i.e. outermost, box for the display of self. All subBoxes assumed to be contained in self.args and self.opDisplay.
Object visible iff root # NIL
parent: BoxTreeData ← NIL, -- root is an absolute Box iff parent = NIL (otherwise relative)
op: ATOM,
domain: Object, -- Domain or View
args: LIST OF BoxTreeData, -- cannot be NIL since this is display of an unpacked Object
assert[ elementOf[op, domain.methods] ]
assert[ resolvableTo[args, opMethod.dynamicSignature] ]
assert[ Object[self] = opMethod[args] ]
opDisplay: LIST OF BoxTreeData ← NIL
selecting one of these BoxTreeDatas implies that (logically) all are selected (user feedback should so indicate?). Editing will take place on just the one actually selected, however.
All of these BoxTreeDatas should belong to domain "OperatorGlyphs". They should only be replacable by an element of the same domain. If that is done, this determines a new candidate self.op. We then proceed top-down to check the assertions above, and reformat self. I.e. we check elementOf[op, domain.methods
It is not assumed that the value of (the data of) each arg here is the same BoxTreeData one would get by application of the EltDisplay proc of the domain of the Object[] of that arg (with the same environment, e.g. unpacking), although at some point in the bottom-up creation of self that BoxTreeData was created; it may be modified by "postprocessing" that we as part of the formatting of this compositeObject
ENDCASE
The basic editing cycle is: select some (selectable, i.e. Object) BoxTree, possibly change its domain, possibly change its opDisplay (and so its op), possibly replace it with a new Object, possibly copy it somewhere, possibly do nothing; update Object of which selection Object is a part; identify new selection. Replacement with a new Object overrides other changes. The update process first updates the selection Object. If this is a newly inserted Object, nothing to do. If domain and/or op changed, then verify the assertions:
assert[ elementOf[op, domain.methods] ]
assert[ resolvableTo[args, opMethod.dynamicSignature] ]
assert[ Object[self] = opMethod[args] ]
and thereby obtain a new BoxTree to replace the originally selected BoxTree. If failure occurs in here, then user is asked what to do - he can either undo the new domain, or delete self. If the latter, then before the selection can possibly be released, some specification of a new Object to replace self must be made. If no such Object is provided, then either a default Object of the new domain, or an Exprs placeholder, is used.
We now have a new BoxTree, i.e. a newSelf. We format it.
If its domain is the same as old self, and if its bounding box fits inside that of old self, then we paint it (and nothing else) and done.
If domain is the same as old self, but newSelf's bounding box doesn't fit inside that of old self (and we decide not to simply rescale it to fit), then we resume an EltDisplay[Object[root]] computation at this point (i.e. so far we can use the existing formattings of siblings, but we invoke a fresh format command ont the parent).
If the domain of newSelf is different from old domain, we startup ("continue") an Object[root] computation from this point.
First, we check whether newSelf is compatible with the appropriate element of parent.opMethod.dynamicSignature. If so, we (possibly) convert newSelf, format it, and proceed as above, depending on whether its bounding box fits inside the old one.
If newSelf's domain is not compatible with the appropriate element of parent.opMethod.dynamicSignature, then we resume an Object[root] computation at this point. E.g. we may lookup parent.op in some other domain, or try to resolve the domains of newSelf and its siblings, etc. If the Object[root] computation succeeds, then the (possibly necessary) reformatting of BoxTrees will occur all the way up to the root, and when we get there and finish, we repaint the entire root Object. A new selection is set (probably at newSelf).
If the Object[root] computation fails at some point, we report the failure and do an automatic undo of this editing cycle.
Note: EltDisplay methods are assumed to produce a formatted result. I.e. the old Meddle Format step is part of any EltDisplay method.
];
BoxTree: TYPE ~ REF BoxTreeRep; -- inside impl module, use rep
END.