MathDisplayImpl.mesa
Mcisaac, July 24, 1987 5:27:19 pm PDT
Implementation for Displaying Mathematical Expressions
DIRECTORY
Convert,
Imager,
ImagerBox,
ImagerFont,
InternalExpr,
List,
MathDisplay,
Rope,
Vector;
MathDisplayImpl: CEDAR PROGRAM
IMPORTS Convert, Imager, ImagerBox, ImagerFont, List, Rope, Vector
EXPORTS MathDisplay
~ BEGIN
Type Redefinitions
EXPR: TYPE ~ REF InternalExpr.EXPR;
Selection: TYPE ~ MathDisplay.Selection;
Type Definitions
BOXTREE: TYPE ~ REF BoxTreeRep;
BoxTreeRep: TYPE ~ RECORD [
bBox: BBOX, -- size of bounding box
relative: SLOT, -- relative to least greatest bounding box
absolute: SLOT, -- relative to outermost boundingbox
subBoxes: LIST OF BOXTREENIL, -- list of boxes bound by this box
parentBox: BOXTREENIL, -- parent bounding box
value: EXPRNIL, -- value of this box
expr: EXPRNIL, -- pointer to expression bound by this box
graphic: GRAPHIC, -- graphical element to be painted
looks: REF ANYNIL, -- italics, bold...
redraw: {no, old, new, copy} ← new -- Redraw algorithm. #not sure about this
];
BBOX: TYPE ~ ImagerBox.Box ← [0,0,0,0];
SLOT: TYPE ~ RECORD [
offset: Vector.VEC ←[0,0], -- offset from origin
scale: REAL ← 1.0 -- scaling factor
];
GRAPHIC: TYPE ~ RECORD [
SELECT type:* FROM
rope => [val: Rope.ROPE],
line => [val: LINE],
ENDCASE
];
LINE: TYPE ~ RECORD [
length: REAL ← 0,
angle: REAL ← 0,
thickness: REAL ← 0.03
];
Global Data
xfont: TYPE ~ ImagerFont.Font; -- imager font name
Display & Formatting
Format: PUBLIC PROC[expr: EXPR] RETURNS [box: BOXTREE] ~ {
Fmt: PROC [box: BOXTREE] ~ {
get format rule. A list of subBoxes
GetFormat[box];
IF box.subBoxes = NIL THEN {
box.bBox ← GraphicBoundingBox[box.graphic]; -- get boundingbox of element
}
ELSE {
recursively format subexpressions
FOR l: LIST OF BOXTREE ← box.subBoxes, l.rest UNTIL l = NIL DO
Fmt[l.first]
ENDLOOP;
size boxes
box.bBox ← SubBoxBoundingBox[box.subBoxes];
compose layout
LayOutBoxes[box.subBoxes];
};
};
box.value ← expr;
Fmt[box]
};
GetFormat: PROC [box: BOXTREE] ~ {
lookup expression in data base and return a list of boxes for it
#dummy routine
OPEN InternalExpr;
lBra: EXPR = atomic[symbol["["]];  
rBra: EXPR = atomic[symbol["]"]];  
comma: EXPR = atomic[symbol[", "]];  
subBoxes : LIST OF BOXTREE ← NIL; 
WITH box.expr SELECT FROM
atm: atomic => box.graphic ← MakeRopeGraphic[atm];
fn: function => {
xi : INT ← 2;
name[
subBoxes ← List.Append[subBoxes, MakeBox[fn.name, fn.name, [0,0], scale]];
subBoxes ← List.Append[subBoxes, MakeBox[NIL, lBra, [1,0], style]];
arg, ...
FOR l: LIST OF EXPR ← fn.subExprs, l.rest UNTIL l = NIL DO
{
subBoxes ← List.Append[subBoxes, MakeBox[l.first, l.first, [xi,0], scale]];
xi ← xi + 1;
IF l.rest # NIL THEN {
subBoxes ← List.Append[subBoxes, MakeBox[comma, NIL, [xi+1,0], scale]];
xi ← xi + 1;
};
};
ENDLOOP;
]
subBoxes ← List.Append[subBoxes, MakeBox[NIL, rBra, [xi,0], scale]];
};
ENDCASE;
box.subBoxes ← subBoxes;
};
MakeRopeGraphic: PROC [atom: InternalExpr.ATOMIC] RETURNS [graphic : rope GRAPHIC] ~ {
Make up graphical element for atom
WITH atom SELECT FROM
i: integer => graphic ← Convert.RopeFromInt[i];
r: real => graphic ← Convert.RopeFromReal[r];
s: symbol => graphic ← Convert.RopeFromAtom[s];
ENDCASE;
};
MakeBox: PROC [value, expr: EXPR, offset: Vector.VEC, scale: REAL] RETURNS [BOXTREE] ~ {
RETURN [NEW[BoxTreeRep ← [value: value, expr: expr, offset: offset, scale: scale]]]
};
GraphicBoundingBox: PROC [graphic: GRAPHIC] RETURNS [bBox: BBOX] ~ {
boundingbox for grapohical element
WITH graphic SELECT FROM
r: rope => bBox ← ImagerFont.RopeBoundingBox[xfont, r];
l: line => bBox ← [0,-0.1, l.length, 0.1] ;
ENDCASE;
};
SubBoxBoundingBox: PROC [boxes: LIST OF BOXTREE] RETURNS [bBox: BBOX] ~ {
compute least greatest bounding box for list of boxes
FOR l: LIST OF BOXTREE ← boxes, l.rest UNTIL l = NIL DO
bBox ← ImagerBox.BoundingBox[bBox, l.first]
ENDLOOP;
};
LayOutBoxes: PROC [boxes: LIST OF BOXTREE] ~ {
compose layout of list of boxes using the relative offsets
#dummy routine
};
Paint: PUBLIC PROC [box: BOXTREE, context: Imager.Context, selections: LIST OF Selection] ~ {
paints a boxed expression in the imager space given by context
IF box.subBoxes = NIL THEN PaintGraphic[box, context] -- paintable leaf
ELSE {
FOR l: LIST OF BOXTREE ← box.subBoxes, l.rest UNTIL l = NIL DO
Calculate absolute scale and offset of the sub-boxes
l.first.absolute.scale ← l.first.relative.scale*box.absolute.scale;
l.first.absolute.offset ← Vector.Add[box.absolute.offset, Vector.Mul[l.first.relative.offset, box.absolute.scale]];
Recursively paint sub-boxes
Paint[l.first, context, selections]
ENDLOOP;
};
if selected, highlight bounding box
FOR l: LIST OF Selection ← selections, l.rest UNTIL l = NIL DO
IF (box.expr = l.first.expr) THEN {
set proper color depending on selection
context.SetColor[l.first.color];
#what is the relation between the offset and the boundingbox?
highlight region
Imager.MaskRectangle[context, [x: absolute.offset.x - (absBox.Extents[].leftExtent + 1), y: absBox.Offset[].y - (absBox.Extents[].descent + 1), w: absBox.Width[] + 1, h: absBox.Height[] + 2]];
reset color to black
context.SetColor[Imager.black];
};
ENDLOOP;
};
PaintGraphic: PROC [box: BOXTREE, context: Imager.Context] ~ {
Paint leaf to screen in absolute coordinates and to absolute scale.
WITH box.graphic SELECT FROM
r: rope => {
Imager.SetXY[context, box.absolute.offset];
Imager.SetFont[context, ImagerFont.Scale[xfont, box.absolute.scale]];
Imager.ShowRope[context, r];
};
l: line => Imager.MaskRectangle[context, [x: box.absolute.Offset.x, y: box.absolute.Offset.y, w: l.lenght*box.absloute.scale, h: thickness]];
ENDCASE ;
};
Install Procs
InstallFonts: PROC [] RETURNS [] ~ {
xfont ← ImagerFont.Find["Xerox/XC1-2-2/Classic"]
};
InstallFmtDB: PROC [] RETURNS [] ~ {
Install format data base
#Dummy routine
};
Start Code
InstallFonts[];
InstallFmtDB[];
END.