ViewExprImpl.mesa
Copyright Ó 1987 by Xerox Corporation. All rights reserved.
Carl Waldspurger, August 29, 1986 2:30:34 pm PDT
Pier, December 10, 1986 5:09:10 pm PST
Arnon, June 10, 1987 8:04:54 am PDT
Rick Beach, September 2, 1987 9:54:25 am PDT
DIRECTORY
AlgebraClasses, Atom, Basics, BigRats, Bools, Buttons, Commander, Complexes, Containers, Convert, Expressions, Evaluator, FS, FSExtras, Icons, Imager, ImagerBackdoor, ImagerTransformation, InputFocus, Ints, IO, Labels, MathBox, MathConstructors, MathDB, MathDisplayExpr, MathExpr, Matrices, Menus, MessageWindow, Parser, Polynomials, PopUpSelection, Real, Reals, RemoteAlgebra, Rope, Rules, Sequences, Sets, TEditDocument, TEditInputOps, TextEdit, TextNode, TiogaAccess, TiogaOps, TiogaOpsDefs, TIPUser, Variables, VariableSequences, Vectors, VFonts, ViewerClasses, ViewerOps, ViewerTools, ViewExpr, ViewExprOps, XRope;
ViewExprImpl: CEDAR PROGRAM
IMPORTS AlgebraClasses, BigRats, Bools, Buttons, Commander, Complexes, Containers, Convert, Expressions, Evaluator, FS, FSExtras, Icons, ImagerBackdoor, InputFocus, Ints, IO, Labels, MathBox, MathConstructors, MathDB, MathDisplayExpr, MathExpr, Matrices, Menus, MessageWindow, Parser, Polynomials, PopUpSelection, Real, Reals, RemoteAlgebra, Rope, Rules, Sequences, Sets, TEditInputOps, TextEdit, TiogaAccess, TiogaOps, TIPUser, Variables, VariableSequences, Vectors, VFonts, ViewerOps, ViewerTools, ViewExprOps, XRope
EXPORTS ViewExpr, TiogaOpsDefs =
BEGIN
OPEN AC: AlgebraClasses, BR: BigRats, VARS: Variables, INTS: Ints, SEQ: Sequences, MAT: Matrices, POL: Polynomials, VEC: Vectors, ViewExpr;
Type Abbreviations From Imported Interfaces
ROPE: TYPE ~ Rope.ROPE;
BOX: TYPE ~ MathBox.BOX;
Viewer: TYPE ~ ViewerClasses.Viewer;
Argument: TYPE ~ MathExpr.Argument;
CompoundClass: TYPE ~ MathExpr.CompoundClass;
EXPR: TYPE ~ MathExpr.EXPR;
DisplayExpr: TYPE ~ MathDisplayExpr.DisplayExpr;
Ref: TYPE = REF NodeBody;
NodeBody: PUBLIC TYPE ~ TextNode.Body;
Object: TYPE ~ AC.Object;
Method: TYPE ~ AC.Method;
Constants
fontToViewerSizeRatio: REAL = 75.0; -- magnify from TeX font units to Viewer pixels
Type Definitions
entryHeight: CARDINAL = 15; -- how tall to make each line of items
entryVSpace: CARDINAL = 8;  -- vertical leading space between lines
entryHSpace: CARDINAL = 10;  -- horizontal space between items in a line
Global Data (global only to this module)
kbBuffer: Parser.KbBuffer;
setSwap: BOOLFALSE;
*** a+-b hack 7/16/87 ***
ignoreNextRightBracket: BOOLFALSE;
CaminoReal Viewer management
MakeCaminoItem: Commander.CommandProc = BEGIN
[] ← CreateCaminoItem["CaminoRealItem"];
END;
CreateCaminoItem: PUBLIC PROC [name: ROPE, object: AlgebraClasses.Object ← NIL] RETURNS [CaminoItem] = BEGIN
expr: EXPRIF object = NIL THEN NIL ELSE NARROW[AC.ApplyNoLkpNoRecastRef[
AC.LookupMethodInStructure[$toExpr, object.class], LIST[object] ], EXPR];
domain: Object ← IF object = NIL THEN NIL ELSE object.class;
my: CaminoItem ← NEW[CaminoItemRec];
myMenu: Menus.Menu ← Menus.CreateMenu[lines: 3];
my.object ← object;
my.outer ← Containers.Create[
info: [
name: name, -- name displayed in the caption
iconic: TRUE,
column: left,-- initially in the left column
menu: myMenu, -- displaying our menu command
scrollable: FALSE -- inhibit user from scrolling contents
]
];
MakeScratchDomain[my, name, domain]; -- build each (sub)viewer in turn
MakeExpr[my, expr];
Menus.AppendMenuEntry[myMenu, Menus.CreateEntry["SetName", SetName, my], 0];
Menus.AppendMenuEntry[myMenu, Menus.CreateEntry["Undo", Undo, my.exprViewer.data], 0];
Menus.AppendMenuEntry[myMenu, Menus.CreateEntry["Scale", Scale, my.exprViewer.data], 0];
Menus.AppendMenuEntry[myMenu, Menus.CreateEntry["Home", Home, my.exprViewer.data], 0];
Menus.AppendMenuEntry[myMenu, Menus.CreateEntry["NewItem", NewItem, my], 0];
Menus.AppendMenuEntry[myMenu, Menus.CreateEntry["ToTioga", ConvertToTioga, my], 0];
Menus.AppendMenuEntry[myMenu, Menus.CreateEntry["SetPtSize", SetPtSize, my], 0];
Menus.AppendMenuEntry[myMenu, Menus.CreateEntry["ToExprRope", ConvertToExprRope, my.exprViewer.data], 0];
Menus.AppendMenuEntry[myMenu, Menus.CreateEntry["ToASRope", ConvertToASRope, my.exprViewer.data], 0];
Menus.AppendMenuEntry[myMenu, Menus.CreateEntry["FromExprRope", ConvertFromExprRope, my.exprViewer.data], 0];
Menus.AppendMenuEntry[myMenu, Menus.CreateEntry[name: "Debug", proc: EnterDebugger, clientData: my.exprViewer.data, guarded: TRUE], 0];
Menus.AppendMenuEntry[myMenu, Menus.CreateEntry["SelectPrimary", SelectEntirePrimary, my.exprViewer.data], 1];
Menus.AppendMenuEntry[myMenu, Menus.CreateEntry["ReplaceWithObject", EnterObject, my.exprViewer.data], 1];
Menus.AppendMenuEntry[myMenu, Menus.CreateEntry["ReplaceWithOperator", ReplaceWithOperator, my.exprViewer.data], 1];
Menus.AppendMenuEntry[myMenu, Menus.CreateEntry["WrapWithOperator", WrapWithOperator, my.exprViewer.data], 1];
Menus.AppendMenuEntry[myMenu, Menus.CreateEntry["SelectCopy", SelectEntireCopy, my.exprViewer.data], 1];
Menus.AppendMenuEntry[myMenu, Menus.CreateEntry["FromTioga", ConvertFromTioga, my], 1];
Menus.AppendMenuEntry[myMenu, Menus.CreateEntry["EvalPrimaryInPlace", EvalPrimaryInPlace, my], 2];
Menus.AppendMenuEntry[myMenu, Menus.CreateEntry["OpPrimaryInPlace", OperatePrimaryInPlace, my], 2];
Menus.AppendMenuEntry[myMenu, Menus.CreateEntry["OpWDInPlace", OperateWorkingDomainInPlace, my], 2];
Menus.AppendMenuEntry[myMenu, Menus.CreateEntry["OpPrimary", OperatePrimaryNew, my], 2];
Menus.AppendMenuEntry[myMenu, Menus.CreateEntry["OpWD", OperateWorkingDomainNew, my], 2];
Menus.AppendMenuEntry[myMenu, Menus.CreateEntry["EvalTiogaInPlace", EvalTiogaInPlace, my], 2];
Menus.AppendMenuEntry[myMenu, Menus.CreateEntry["Algebra", DoAlgebra, my], 2];
ViewerOps.SetMenu[my.outer, myMenu]; -- hint our desired height
ViewerOps.SetOpenHeight[my.outer, my.height]; -- hint our desired height (SampleTool)
ViewerOps.PaintViewer[my.outer, all];-- reflect above change
ViewerOps.PaintViewer[my.exprViewer, client];-- get expression viewer sized
RepaintViewer[my.exprViewer];
RETURN[my];
END;
MakeScratchDomain: PROC [caminoItem: CaminoItem, name: ROPE, domain: Object] = BEGIN
scratchPadButton, objectDomainButton, workingDomainButton: Buttons.Button;
initialName: Rope.ROPE;
initialDomain: Rope.ROPE;
initialName ← IF name = NIL THEN " " ELSE name;
initialDomain ← IF domain = NIL THEN " " ELSE NARROW[AC.ApplyNoLkpNoRecastRef[
AC.LookupMethodInStructure[$shortPrintName, domain], LIST[domain] ], ROPE];
caminoItem.height ← caminoItem.height + entryVSpace; -- space down from the top of the viewer
caminoItem.name ← initialName;
objectDomainButton ← Buttons.Create[
info: [
name: "Result Domain:",
wy: caminoItem.height,
default the width so that it will be computed for us --
ww:, -- default the width so that it will be computed for us
wh: entryHeight, -- specify rather than defaulting so line is uniform
parent: caminoItem.outer,
border: TRUE],
clientData: caminoItem, -- this will be passed to our button proc
proc: Null];
caminoItem.objectDomainViewer ← Labels.Create[
info: [
name: initialDomain, -- initial contents
wx: objectDomainButton.wx + objectDomainButton.ww + entryHSpace,
wy: caminoItem.height,
ww: 30*VFonts.CharWidth['0], -- 30 digits worth of width
wh: entryHeight,
parent: caminoItem.outer,
border: TRUE
]
];
workingDomainButton ← Buttons.Create[
info: [
name: "Working Domain:",
wy: caminoItem.height,
wx: caminoItem.objectDomainViewer.wx + caminoItem.objectDomainViewer.ww + entryHSpace,
default the width so that it will be computed for us --
ww:, -- default the width so that it will be computed for us
wh: entryHeight, -- specify rather than defaulting so line is uniform
parent: caminoItem.outer,
border: TRUE],
clientData: caminoItem, -- this will be passed to our button proc
proc: SetWorkingDomain];
caminoItem.workingDomainViewer ← Labels.Create[
info: [
name: initialDomain, -- initial contents
wx: workingDomainButton.wx + workingDomainButton.ww + entryHSpace,
wy: caminoItem.height,
ww: 30*VFonts.CharWidth['0], -- 30 digits worth of width
wh: entryHeight,
parent: caminoItem.outer,
border: TRUE
]
];
caminoItem.workingDomain ← domain;
caminoItem.height ← caminoItem.height + entryHeight + entryVSpace; -- interline spacing
scratchPadButton ← Buttons.Create[
info: [
name: "ScratchPad:",
wy: caminoItem.height,
default the width so that it will be computed for us --
wh: entryHeight, -- specify rather than defaulting so line is uniform
parent: caminoItem.outer,
border: TRUE ],
proc: PromptScratch,
clientData: caminoItem]; -- this will be passed to our button proc
caminoItem.scratchPadViewer ← ViewerTools.MakeNewTextViewer[
info: [
parent: caminoItem.outer,
wx: scratchPadButton.wx + scratchPadButton.ww + entryHSpace,
wy: caminoItem.height+2,
ww: 80*VFonts.CharWidth['0], -- 80 digits worth of width
wh: entryHeight,
data: "", -- initial contents
scrollable: FALSE,
border: TRUE] ];
scratchPadButton ← Buttons.Create[
info: [
name: "Scratch:",
wx: caminoItem.nameViewer.wx + caminoItem.nameViewer.ww + entryHSpace,
wy: caminoItem.height,
wh: entryHeight, -- specify rather than defaulting so line is uniform
parent: caminoItem.outer,
border: TRUE],
proc: PromptScratch,
clientData: caminoItem]; -- this will be passed to our button proc
caminoItem.scratchPadViewer ← ViewerTools.MakeNewTextViewer[
info: [
parent: caminoItem.outer,
wx: scratchPadButton.wx + scratchPadButton.ww + entryHSpace,
wy: caminoItem.height,
ww: 30*VFonts.CharWidth['0], -- 30 digits worth of width
wh: entryHeight,
data: " ", -- initial contents
scrollable: FALSE,
border: TRUE] ];
caminoItem.height ← caminoItem.height + entryHeight + entryVSpace; -- interline spacing
END;
PromptScratch: Buttons.ButtonProc = BEGIN
force the selection into the user input field
caminoItem: CaminoItem ← NARROW[clientData]; -- get our data
ViewerTools.SetSelection[caminoItem.scratchPadViewer];  -- force the selection
END;
Null: Buttons.ButtonProc = BEGIN
END;
MakeExpr: PROC [caminoItem: CaminoItem, expr: EXPRNIL] = BEGIN
xTab: INTEGER = 10;
rule: Rules.Rule ← Rules.Create[
info: [ -- create a bar to separate sections 1 and 2
parent: caminoItem.outer,
wy: caminoItem.height,
ww: caminoItem.outer.cw,
wh: 2]];
Containers.ChildXBound[caminoItem.outer, rule]; -- constrain rule to be width of parent
caminoItem.height ← caminoItem.height + 2; -- spacing after rule
caminoItem.exprViewer ← CreateExprViewer[
parentItem: caminoItem,
x: 0,
y: caminoItem.height,
w: caminoItem.outer.cw,
h: caminoItem.outer.wh - caminoItem.height,
expr: expr ];
Containers.ChildXBound[caminoItem.outer, caminoItem.exprViewer];
Containers.ChildYBound[caminoItem.outer, caminoItem.exprViewer];
caminoItem.height ← caminoItem.outer.wh; -- extra space at end
END;
SetName: Buttons.ButtonProc = BEGIN
attach the name to the Camino item and its container, also to object if any
caminoItem: CaminoItem ← NARROW[clientData]; -- get our data
caminoItem.name ← ViewerTools.GetContents[caminoItem.scratchPadViewer];  -- get name
caminoItem.outer.name ← caminoItem.name;
IF caminoItem.object # NIL THEN caminoItem.object.name ← caminoItem.name;
ViewerOps.PaintViewer[caminoItem.outer, all];    -- reflect change
END;
NewItem: Menus.MenuProc ~ {
caminoItem: CaminoItem ← NARROW[clientData];
newItem: CaminoItem;
domain: Object ← caminoItem.workingDomain;
newItem ← CreateCaminoItem["CaminoRealItem", NIL];
newItem.workingDomain ← domain;
IF domain#NIL THEN Labels.Set[newItem.workingDomainViewer, domain.class.shortPrintName[domain] ];
};
ExprViewer management
CreateExprViewer: PROC[parentItem: CaminoItem, x, y, w, h: INTEGER, expr: EXPRNIL] RETURNS[Viewer] ~ {
effects: Creates a new instance of an expression viewer.
Viewer will contain math expression expr. If expr = NIL, then
Viewer will contain an empty "placeholder".
v: Viewer ← NIL; -- expression viewer instance
s: ExprViewerData; -- expression viewer state
expression: EXPR ← expr; -- intial expression to display in viewer
displayExpr: DisplayExpr ← NIL; -- display form of expr
displayBox: BOXNIL; -- box for displayExpr
If expr to display is defaulted, use empty placeholder
IF expression = NIL THEN expression ← MathConstructors.MakePlaceHolder[];
displayExpr ← MathDisplayExpr.DisplayExprFromExpr[expression];
displayBox ← displayExpr.Format[normal];
instantiate new viewer
v ← ViewerOps.CreateViewer[
flavor: $expr,
info: [
parent: parentItem.outer,
wx: x, wy: y, ww: w, wh:h,
scrollable: TRUE,
hscrollable: TRUE]
];
set its state
s ← NARROW[v.data];
s.parentItem ← parentItem;
s.displayExpr ← displayExpr;
s.lastDisplayExpr ← displayExpr; -- for UNDO
s.displayBox ← displayBox;
paint new viewer
ViewerOps.PaintViewer[v, all];
return the newly spawned viewer
RETURN[v];
};
InitializeExprViewer: ViewerClasses.InitProc ~ {
effects: Initializes an expression viewer instance.
self.data ← NEW[ExprViewerDataRec ← [
exprViewer: self,
offsetX: 0.0,
offsetY: 0.0,
scale: 1.0,
displayExpr: NIL,
displayBox: NIL,
physicalBox: NIL]];
};
VerticalScroll: ViewerClasses.ScrollProc ~ {
effects: Performs verical scrolling of an expression viewer.
s: ExprViewerData ← NARROW[self.data]; -- get viewer state info
compute current top & bottom percentage visible metrics
topPercentage: INTEGER ← 100 + Real.Round[((-self.ch + (s.physicalBox.Offset[].y - s.physicalBox.Extents[].descent)) / s.physicalBox.Height[]) * 100];
bottomPercentage: INTEGER ← 100 - Real.Round[((s.physicalBox.Extents[].descent - s.physicalBox.Offset[].y) / s.physicalBox.Height[]) * 100];
SELECT op FROM
query => {
RETURN[top: MIN[100, MAX[0, topPercentage]],
bottom: MAX[0, MIN[100, bottomPercentage]]];
};
up => {
s.offsetY ← s.offsetY + amount;
ViewerOps.PaintViewer[s.exprViewer, client];
};
down => {
s.offsetY ← s.offsetY - amount;
ViewerOps.PaintViewer[s.exprViewer, client];
};
thumb => RETURN[];
ENDCASE => ERROR;
};
HorizontalScroll: ViewerClasses.HScrollProc ~ {
effects: Performs horizontal scrolling of an expression viewer.
s: ExprViewerData ← NARROW[self.data]; -- get viewer state info
compute current left & right percentage visible metrics
leftPercentage: INTEGER ← Real.Round[((s.physicalBox.Extents[].leftExtent - s.physicalBox.Offset[].x) / s.physicalBox.Width[]) * 100];
rightPercentage: INTEGER ← Real.Round[((self.cw - (s.physicalBox.Offset[].x - s.physicalBox.Extents[].leftExtent)) / s.physicalBox.Width[]) * 100];
SELECT op FROM
query => {
RETURN[left: MIN[100, MAX[0, leftPercentage]],
right: MAX[0, MIN[100, rightPercentage]]];
};
left => {
s.offsetX ← s.offsetX - amount;
ViewerOps.PaintViewer[s.exprViewer, client];
};
right => {
s.offsetX ← s.offsetX + amount;
ViewerOps.PaintViewer[s.exprViewer, client];
};
thumb => RETURN[];
ENDCASE => ERROR;
};
DestroyExprViewer: ViewerClasses.DestroyProc ~ {
effects: Peforms orderly termination of an expression viewer.
s: ExprViewerData ← NARROW[self.data];
if self contains any selections, unselect them
ViewExprOps.UnSelectViewer[self];
remove self from paint queue
ViewExprOps.PaintDequeue[self];
s.exprViewer ← NIL; -- break up circular ref for GC
};
NotifyExprViewer: ViewerClasses.NotifyProc ~ {
effects: Performs actions based on parsed TIP events.
only SetSelection ops require knowledge of the viewer who's NotifyProc is being invoked, i.e. only SetSelection ops need to be done here, rather than in HandleUserAction
[] ← InputFocus.SetInputFocus[self]; -- grab the input focus so keyboard events get parsed
WITH input.first SELECT FROM
xy: TIPUser.TIPScreenCoords => {
s: ExprViewerData ← NARROW[self.data];
SELECT input.rest.first FROM
$PrimarySelect => {
ViewExprOps.Select[$primary, s.exprViewer, MathDisplayExpr.DisplayExprFromCoords[s.displayExpr, xy.mouseX, xy.mouseY ! MathDisplayExpr.noSelection => {ViewExprOps.UnSelect[$primary]; CONTINUE}]];
};
$MoveSelect => {
can't make a move selection w/o an existing primary selection
IF ~ViewExprOps.Active[$primary] THEN {
MessageWindow.Append["Make a primary selection first.", TRUE];
MessageWindow.Blink[];
RETURN;
};
ViewExprOps.Select[$move, s.exprViewer, MathDisplayExpr.DisplayExprFromCoords[s.displayExpr, xy.mouseX, xy.mouseY ! MathDisplayExpr.noSelection => {ViewExprOps.UnSelect[$move]; CONTINUE}]];
};
$CopySelect => {
can't make a copy selection w/o an existing primary selection
IF ~ViewExprOps.Active[$primary] THEN {
MessageWindow.Append["Make a primary selection first.", TRUE];
MessageWindow.Blink[];
RETURN;
};
ViewExprOps.Select[$copy, s.exprViewer, MathDisplayExpr.DisplayExprFromCoords[s.displayExpr, xy.mouseX, xy.mouseY ! MathDisplayExpr.noSelection => {ViewExprOps.UnSelect[$copy]; CONTINUE}]];
};
ENDCASE => HandleUserAction[input.rest.first, self];
};
ENDCASE => HandleUserAction[input.first, self]; -- Tip table didn't do anything with this character; input.first is a REF CHAR
flush any pending paint requests
ViewExprOps.FlushPaintQueue[];
};
SelectionColor: PROC[flavor: ATOM] RETURNS[Imager.Color] ~ {
effects: Returns the color associated with flavor.
If no such association exists, uses "$Invert" color.
RETURN[
SELECT flavor FROM
$primary => ImagerBackdoor.invert,
$copy => ImagerBackdoor.MakeStipple[8421H, TRUE],
$move => ImagerBackdoor.MakeStipple[8020H, TRUE],
$keyboard => ImagerBackdoor.MakeStipple[00F0H, TRUE],
ENDCASE => ImagerBackdoor.invert
];
};
PaintExprViewer: ViewerClasses.PaintProc ~ { -- PROC [self: Viewer, context: Imager.Context, whatChanged: REF, clear: BOOL] RETURNS [quit: BOOL ← FALSE];
effects: Repaints contents of an expression viewer.
local declarations
scaleFactor: REAL ← fontToViewerSizeRatio; -- scaling factor
s: ExprViewerData ← NARROW[self.data];
highlight: LIST OF MathDisplayExpr.Selection ← NIL;
IF (s.displayExpr = NIL) OR (s.displayBox = NIL) THEN RETURN; -- nothing to paint
modify scale factor by user-specified growth factor
scaleFactor ← scaleFactor * s.scale;
s.physicalBox ← MathBox.ChangeOffset[MathBox.Scale[s.displayBox, [scaleFactor, scaleFactor]],
[s.offsetX + (scaleFactor * s.displayBox.Extents.leftExtent), s.offsetY + (scaleFactor * s.displayBox.Extents.descent)]];
cons up list of selections to highlight
FOR l: LIST OF ATOMLIST[$primary, $copy, $move, $keyboard], l.rest UNTIL l = NIL DO
IF ViewExprOps.Active[l.first] THEN {
selectedViewer: Viewer ← NIL;
selectedExpr: DisplayExpr ← NIL;
[selectedViewer, selectedExpr] ← ViewExprOps.GetSelection[l.first];
IF selectedViewer = s.exprViewer THEN highlight ← CONS[[selectedExpr, SelectionColor[l.first]], highlight];
};
ENDLOOP;
spray the bits onto screen via imager
MathDisplayExpr.Paint[s.displayExpr, context, s.physicalBox, highlight];
};
RepaintViewer: PUBLIC PROC[viewer: Viewer] ~ {
ViewExprOps.PaintEnqueue[viewer];
ViewExprOps.FlushPaintQueue[];
};
Home: Menus.MenuProc ~ {
effects: Repaints viewer after zeroing all offsets from scrolling.
s: ExprViewerData ← NARROW[clientData];
s.offsetX ← 0.0;
s.offsetY ← 0.0;
ViewerOps.PaintViewer[s.exprViewer, client];
ViewerOps.PaintViewer[s.exprViewer, client]; -- seems necessary to get it now
};
Scale: Menus.MenuProc ~ {
effects: Changes viewer scale factor.
If selected with left button, scale ← scale * 1.5,
right button, scale ← scale / 1.5,
middle button, scale ← 1.0
s: ExprViewerData ← NARROW[clientData];
SELECT mouseButton FROM
red => {s.scale ← s.scale * 1.5};
yellow => {s.scale ← 1.0};
blue => {s.scale ← s.scale / 1.5};
ENDCASE => ERROR;
ViewerOps.PaintViewer[s.exprViewer, client];
};
Undo: Menus.MenuProc ~ {
effects: "Undoes" last action on viewer by restoring previously saved state.
s: ExprViewerData ← NARROW[clientData];
UndoViewer[s.exprViewer];
};
UndoViewer: PROC[viewer: Viewer] ~ {
modifies: viewer
effects: Restores viewer state (expression & box info) to previous state.
state: ExprViewerData ← NARROW[viewer.data]; -- get current state
cancel any current selections in viewer since UNDO may invalidate them
ViewExprOps.UnSelectViewer[viewer];
replace current expr by last saved expr, set primary selection to whole thing
SetViewerDisplayExpr[viewer, state.lastDisplayExpr];
ViewExprOps.Select[$primary, viewer, state.displayExpr];
now paint the viewer so UNDO is seen
ViewerOps.PaintViewer[viewer, client];
};
RegisterExprViewerClass: PROC ~ {
effects: Registers a new viewer class for expression viewers.
ViewerOps.RegisterViewerClass[
$expr,
NEW[ViewerClasses.ViewerClassRec ← [
init: InitializeExprViewer,
destroy: DestroyExprViewer,
notify: NotifyExprViewer,
tipTable: TIPUser.InstantiateNewTIPTable["ViewExpr.tip"],
icon: Icons.NewIconFromFile["Meddle.icons", 0],
paint: PaintExprViewer,
scroll: VerticalScroll,
hscroll: HorizontalScroll
]]
];
};
Meddle (CaminoReal) Selections management
CopySecondaryToPrimary: PROC[] ~ {
effects: If both primary and secondary selections are active,
replaces primary selection by secondary selection.
local declarations
replacement, primaryExpr, copyExpr: DisplayExpr ← NIL;
primaryViewer, copyViewer: Viewer ← NIL;
IF ~(ViewExprOps.Active[$primary] AND ViewExprOps.Active[$copy]) THEN {
MessageWindow.Append["Insufficient Selections for Copy", TRUE];
MessageWindow.Blink[];
RETURN;
};
[primaryViewer, primaryExpr] ← ViewExprOps.GetSelection[$primary];
[copyViewer, copyExpr] ← ViewExprOps.GetSelection[$copy];
replacement ← MathDisplayExpr.Copy[copyExpr];
ReplaceInViewer[primaryViewer, primaryExpr, replacement];
select ops below will repaint viewers to reflect replacement
ViewExprOps.UnSelect[$primary];
ViewExprOps.UnSelect[$copy];
};
SwapSecondaryAndPrimary: PROC[] ~ {
effects: If both primary and secondary selections are active,
swap primary and secondary selections.
local declarations
moveReplacement, primaryReplacement, primaryExpr, moveExpr: DisplayExpr ← NIL;
moveViewer, primaryViewer: Viewer ← NIL;
ok: BOOL;
[ok, primaryViewer, primaryExpr] ← CheckSelection[$primary];
IF ~ok THEN RETURN;
[ok, moveViewer, moveExpr] ← CheckSelection[$move];
IF ~ok THEN RETURN;
primaryReplacement ← MathDisplayExpr.Copy[primaryExpr];
moveReplacement ← MathDisplayExpr.Copy[moveExpr];
IF moveViewer = primaryViewer THEN {
same viewer, so use ReplaceN to make two simultaneous replacements
state: ExprViewerData ← NARROW[primaryViewer.data];
doubleReplacement: DisplayExpr ← MathDisplayExpr.ReplaceN[state.displayExpr, LIST[[old: primaryExpr, new: moveReplacement], [old: moveExpr, new: primaryReplacement]]];
SetViewerDisplayExpr[primaryViewer, doubleReplacement]; -- mutate viewer expression
ViewExprOps.PaintEnqueue[primaryViewer];
}
ELSE {
different viewers, so do one replacement at a time
ReplaceInViewer[primaryViewer, primaryExpr, moveReplacement];
ReplaceInViewer[moveViewer, moveExpr, primaryReplacement];
select ops below will repaint viewers to reflect replacement
ViewExprOps.UnSelect[$primary];
ViewExprOps.UnSelect[$move];
};
};
MoveSecondaryToPrimary: PROC[] ~ {
effects: If both primary and move selections are active,
replaces primary selection by move selection and
deletes secondary selection.
local declarations
moveReplacement, primaryExpr, moveExpr: DisplayExpr ← NIL;
moveViewer, primaryViewer: Viewer ← NIL;
IF ~(ViewExprOps.Active[$primary] AND ViewExprOps.Active[$move]) THEN {
MessageWindow.Append["Insufficient Selections for Move", TRUE];
MessageWindow.Blink[];
RETURN;
};
[primaryViewer, primaryExpr] ← ViewExprOps.GetSelection[$primary];
[moveViewer, moveExpr] ← ViewExprOps.GetSelection[$move];
moveReplacement ← MathDisplayExpr.Copy[moveExpr];
IF moveViewer = primaryViewer THEN {
same viewer, so use ReplaceN to make two simultaneous replacements
state: ExprViewerData ← NARROW[primaryViewer.data];
placeholder: DisplayExpr ← MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakePlaceHolder[]];
doubleReplacement: DisplayExpr ← MathDisplayExpr.ReplaceN[state.displayExpr, LIST[[old: primaryExpr, new: moveReplacement], [old: moveExpr, new: placeholder]]];
SetViewerDisplayExpr[primaryViewer, doubleReplacement]; -- mutate viewer expression
ViewExprOps.PaintEnqueue[primaryViewer];
}
ELSE {
different viewers, so do one replacement at a time
ReplaceInViewer[primaryViewer, primaryExpr, moveReplacement];
select ops below will repaint viewers to reflect replacement
ViewExprOps.UnSelect[$primary];
DeleteSelection[$move, FALSE];
};
};
CheckSelection: PROC [flavor: ATOM, thisViewer: Viewer ← NIL] RETURNS [ok: BOOLTRUE, selectionViewer: Viewer, selectionExpr: DisplayExpr] ~ {
[selectionViewer, selectionExpr] ← ViewExprOps.GetSelection[flavor ! ViewExprOps.noSelection => {ok ← FALSE; CONTINUE}];
IF ~ok AND flavor=$primary THEN {
ok ← TRUE;
[selectionViewer, selectionExpr] ← ViewExprOps.GetSelection[$keyboard ! ViewExprOps.noSelection => {ok ← FALSE; CONTINUE}]; -- $keyboard selection is effectively the primary selection
};
IF ~ok OR (thisViewer#NIL AND selectionViewer # thisViewer) THEN {
msg: ROPE ← Rope.Cat[
"Make a CaminoReal ",
Convert.RopeFromAtom[from: flavor, quote: FALSE],
" selection"];
IF thisViewer#NIL AND selectionViewer # thisViewer THEN
msg ← Rope.Concat[msg, " in this viewer"];
MessageWindow.Append[msg, TRUE];
MessageWindow.Blink[];
RETURN[FALSE, NIL, NIL]; -- no selection to replace
};
};
SelectEntirePrimary: Menus.MenuProc ~ {
effects: Make primary selection entire current Display Expression.
s: ExprViewerData ← NARROW[clientData];
SelectEntireViewer[s.exprViewer, $primary];
};
SelectEntireCopy: Menus.MenuProc ~ {
effects: Make primary selection entire current Display Expression.
s: ExprViewerData ← NARROW[clientData];
SelectEntireViewer[s.exprViewer, $copy];
};
SelectEntireViewer: PROC[viewer: Viewer, flavor: ATOM] ~ {
modifies: viewer
effects: Make flavor selection entire current Display Expression.
state: ExprViewerData ← NARROW[viewer.data]; -- get current state
cancel any current selections in viewer since UNDO may invalidate them
ViewExprOps.UnSelectViewer[viewer];
Select entire current display expr
ViewExprOps.Select[flavor, viewer, state.displayExpr];
grab the input focus so keyboard events get parsed
[] ← InputFocus.SetInputFocus[viewer];
now paint the viewer so new selection is seen
ViewerOps.PaintViewer[viewer, client];
};
ReplaceInViewer: PROC[viewer: Viewer, old, new: DisplayExpr] ~ {
modifies: viewer
effects: Replaces old in the display expression for viewer with new.
Reformats the display expression for viewer.
Note that currently doesn't consult or alter Selections.
state: ExprViewerData ← NARROW[viewer.data];
replacement: DisplayExpr ← MathDisplayExpr.Replace[state.displayExpr, old, new];
SetViewerDisplayExpr[viewer, replacement];
};
SetViewerDisplayExpr: PROC[viewer: Viewer, replacement: DisplayExpr] ~ {
modifies: viewer
effects: Sets and formats display expression for viewer to replacement.
intent: ALL assignments to viewer display expressions and boxes should
go thru this procedure to keep "UNDO" information valid.
state: ExprViewerData ← NARROW[viewer.data]; -- get current state
state.lastDisplayExpr ← state.displayExpr; -- old gets current
state.displayExpr ← replacement; -- current gets new
state.displayBox ← state.displayExpr.Format[normal]; -- format new
};
DeleteSelection: PROC[flavor: ATOM, reselect: BOOLTRUE] ~ {
effects: Deletes selection of type flavor, if active.
Replaces selection with an expression "placeholder".
This placeholder remians selected iff reselect is TRUE.
replacement, selectedExpr: DisplayExpr ← NIL;
selectedViewer: Viewer ← NIL;
IF ~ViewExprOps.Active[flavor] THEN RETURN; -- return w/o action if seln not active
[selectedViewer, selectedExpr] ← ViewExprOps.GetSelection[flavor];
replacement ← MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakePlaceHolder[]];
ReplaceInViewer[selectedViewer, selectedExpr, replacement];
IF reselect THEN {
IF flavor#$keyboard THEN ViewExprOps.Select[flavor, selectedViewer, replacement]
ELSE { -- the placeholder for deleted KB selection becomes the primary selection
ViewExprOps.UnSelect[$keyboard];
ResetKBBuffer[];
ViewExprOps.Select[$primary, selectedViewer, replacement];
};
}
ELSE ViewExprOps.UnSelect[flavor];
};
ResetKBBuffer: PROC ~ {
kbBuffer ← [type: none, data: "", savedWrapArg: NIL]; -- reset kbBuffer
};
ChangeSelectionFlavor: PROC[oldFlavor, newFlavor: ATOM] ~ {
effects: Rename oldFlavor selection, if active, to newFlavor.
selectedViewer: Viewer;
selectedExpr: DisplayExpr;
IF ~ViewExprOps.Active[oldFlavor] THEN RETURN; -- return w/o action if seln not active
[selectedViewer, selectedExpr] ← ViewExprOps.GetSelection[oldFlavor];
ViewExprOps.UnSelect[oldFlavor];
ViewExprOps.Select[newFlavor, selectedViewer, selectedExpr];
};
PopUpMenu utilities
GetPopUpMenuMethod: PROC [selection: INT, names: LIST OF ROPE, menuValueList: LIST OF Method] RETURNS [value: Method ← NIL, name: ROPENIL] ~ {
Like GetPopUpMenuAtom except for Methods
FOR l: LIST OF Method ← menuValueList, l.rest UNTIL l = NIL DO
selection ← selection - 1;
IF selection = 0 THEN {value ← l.first; name ← names.first; EXIT};
names ← names.rest;
ENDLOOP;
RETURN[value, name];
};
GetPopUpMenuAtom: PROC [selection: INT, menuValueList: LIST OF ATOM] RETURNS [value: ATOMNIL] ~ {
FOR l: LIST OF ATOM ← menuValueList, l.rest UNTIL l = NIL DO
selection ← selection - 1;
IF selection = 0 THEN {value ← l.first; EXIT};
ENDLOOP;
RETURN[value];
};
PopUpMenu-driven Expression Editing
EnterObject: Menus.MenuProc ~ {
effects: Replaces active selection with an atomic expression.
Returns without action if any errors (e.g. parsing) occur.
local declarations
replacement: DisplayExpr ← NIL;
opNames: LIST OF ROPELIST["variable", "lowGreekVar", "uppGreekVar", "specialCharacter", "bool", "integer", "rational", "real", "complex", "set", "sequence", "vector", "matrix", "block", "parseRope"];
selection: INT ← 0;
ok: BOOLTRUE;
primaryViewer: Viewer ← NIL;
primaryExpr: DisplayExpr ← NIL;
textSelection: ROPENIL;
constants
variable: INT = 1;
lowGreekVar: INT = 2;
uppGreekVar: INT = 3;
specialCharacter: INT = 4;
bool: INT = 5;
integer: INT = 6;
rational: INT = 7;
real: INT = 8;
complex: INT = 9;
set: INT = 10;
sequence: INT = 11;
vector: INT = 12;
matrix: INT = 13;
block: INT = 14;
parseRope: INT = 15;
MakeHat: PUBLIC PROC[] RETURNS[EXPR] ~ {
effects: Constructs and returns an expression for +infinity.
RETURN[MathExpr.MakeAtomicExpr[$hat, XRope.FromChar['^, XRope.roman]]];
};
s: ExprViewerData ← NARROW[clientData];
[ok, primaryViewer, primaryExpr] ← CheckSelection[$primary, s.exprViewer];
IF ~ok THEN RETURN;
do pop-up menu
selection ← PopUpSelection.Request[header: "Choose Object", choice: opNames];
{
ENABLE MathConstructors.badFormat, Convert.Error => {
MessageWindow.Append["Input format error.", TRUE];
MessageWindow.Blink[];
GOTO abort;
};
get text viewer selection, if any (not all opNames use this)
textSelection ← ViewerTools.GetSelectionContents[];
SELECT selection FROM
parseRope => PrimarySelectionFromRope[textSelection];
bool => {
replacement ← MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakeBool[textSelection]];
};
integer => {
replacement ← MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakeInt[textSelection]];
};
rational => {
replacement ← MathDisplayExpr.DisplayExprFromExpr[
MathConstructors.MakeFraction[
MathConstructors.MakeInt["0"],
MathConstructors.MakeInt["1"]
] ];
};
real => {
replacement ← MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakeReal[Convert.RealFromRope[textSelection]]];
};
complex => {
replacement ← MathDisplayExpr.DisplayExprFromExpr[
MathConstructors.MakeComplex[
MathConstructors.MakeReal[Convert.RealFromRope["0.0"] ],
MathConstructors.MakeReal[Convert.RealFromRope["0.0"] ]
] ];
};
variable => {
replacement ← MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakeVariable[textSelection]];
};
lowGreekVar => {
local declarations
greekName: ROPENIL;
greekChoices: LIST OF ROPELIST["alpha", "beta", "gamma", "delta", "epsilon", "zeta", "eta", "theta", "iota", "kappa", "lambda", "mu", "nu", "xi", "pi", "rho", "sigma", "tau", "upsilon", "phi", "chi", "psi", "omega"];
display a second pop-up menu to choose greek letter from
selection ← PopUpSelection.Request[header: "Choose Variable", choice: greekChoices];
IF selection < 1 THEN RETURN; -- timeout or no selection
FOR l: LIST OF ROPE ← greekChoices, l.rest UNTIL l = NIL DO
match selection (INT) with class name (ROPE -> ATOM)
selection ← selection - 1;
IF selection = 0 THEN {greekName ← l.first; EXIT};
ENDLOOP;
replacement ← MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakeGreekVar[greekName]];
};
uppGreekVar => {
local declarations
greekName: ROPENIL;
greekChoices: LIST OF ROPELIST["Gamma", "Delta", "Theta", "Lambda", "Xi", "Pi", "Sigma", "Upsilon", "Phi", "Psi", "Omega"];
display a second pop-up menu to choose greek letter from
selection ← PopUpSelection.Request[header: "Choose Variable", choice: greekChoices];
IF selection < 1 THEN RETURN; -- timeout or no selection
FOR l: LIST OF ROPE ← greekChoices, l.rest UNTIL l = NIL DO
match selection (INT) with class name (ROPE -> ATOM)
selection ← selection - 1;
IF selection = 0 THEN {greekName ← l.first; EXIT};
ENDLOOP;
replacement ← MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakeGreekVar[greekName]];
};
specialCharacter => {
local declarations
specialCharName: ROPENIL;
specialCharChoices: LIST OF ROPELIST["infinity", "rightArrow", "bar", "perp", "hat"];
infinity: INT = 1;
rightArrow: INT = 2;
bar: INT = 3;
perp: INT = 4;
hat: INT = 5;
display a second pop-up menu to choose specialCharacter from
selection ← PopUpSelection.Request[header: "Choose Special Char", choice: specialCharChoices];
SELECT selection FROM
infinity => {
replacement ← MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakeInfinity[]];
};
rightArrow => {
replacement ← MathDisplayExpr.DisplayExprFromExpr[MathExpr.MakeAtomicExpr[$rightArrow, "\041"] ];
};
bar => {
replacement ← MathDisplayExpr.DisplayExprFromExpr[MathExpr.MakeAtomicExpr[$bar, "\000"] ];
};
perp => {
replacement ← MathDisplayExpr.DisplayExprFromExpr[MathExpr.MakeAtomicExpr[$perp, "\077"] ];
};
hat => {
replacement ← MathDisplayExpr.DisplayExprFromExpr[MakeHat[]];
};
ENDCASE => RETURN;
};
set, vector, sequence, block => {
effects: Replaces active primary selection with a template for a sequence or vector
whose size and type (row, col) is chosen from a series of pop-up menus.
Returns without action if any errors occur.
oneToTen: LIST OF ROPELIST["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"];
dimension: INT ← 0;
elements: LIST OF EXPRNIL;
row: INT ← 0; -- =1 => row vector, =2 => col vector, ELSE => invalid
rowVec: BOOLFALSE; -- TRUE iff vector is a row vector
ok: BOOLTRUE;
row ← PopUpSelection.Request[header: "Type", choice: LIST["row", "column"]];
IF (row < 1) OR (row > 2) THEN RETURN; -- no selection or timeout
IF row = 1 THEN rowVec ← TRUE;
dimension ← PopUpSelection.Request[header: "Dimension", choice: oneToTen];
IF (dimension < 1) THEN RETURN; -- no selection or timeout
FOR i: INT IN [1..dimension] DO
elements ← CONS[MathConstructors.MakeInt["0"], elements]; -- zero entries
ENDLOOP;
SELECT selection FROM
set => replacement ← MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakeSet[dimension, elements, rowVec]];
block => replacement ← MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakePoint[dimension, elements, rowVec]];
vector => replacement ← MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakeVector[dimension, elements, rowVec]];
sequence => replacement ← MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakeSequence[dimension, elements, rowVec]];
ENDCASE;
};
matrix => {
effects: Replaces active primary selection with a template for a matrix
whose size is chosen from a series op pop-up menus.
Returns without action if any errors occur.
oneToTen: LIST OF ROPELIST["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"];
nRows, nCols: INT ← 0;
rows: LIST OF LIST OF EXPRNIL;
ok: BOOLTRUE;
nRows ← PopUpSelection.Request[header: "# Rows", choice: oneToTen];
IF (nRows < 1) THEN RETURN; -- no selection or timeout
nCols ← PopUpSelection.Request[header: "# Cols", choice: oneToTen];
IF (nCols < 1) THEN RETURN; -- no selection or timeout
rows ← NIL; -- cons up list of rows
FOR r:INT IN [1..nRows] DO
currentRow: LIST OF EXPRNIL; -- cons up list of elements
FOR c:INT IN [1..nCols] DO
currentRow ← CONS[MathConstructors.MakeInt["0"], currentRow]; -- zero entries
ENDLOOP;
rows ← CONS[currentRow, rows];
ENDLOOP;
replacement ← MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakeMatrix[nRows, nCols, rows]];
};
ENDCASE => RETURN;
replace active selection
IF selection#parseRope THEN {
ViewExprOps.UnSelect[$primary]; -- unselect currently active selection
ReplaceInViewer[primaryViewer, primaryExpr, replacement]
};
repaint viewer to reflect replacement
ViewerOps.PaintViewer[s.exprViewer, client];
};
EXITS
abort => NULL;
};
ReplaceWithOperator: Menus.MenuProc ~ {
ReplaceOrWrap[clientData: clientData, replace: TRUE];
};
WrapWithOperator: Menus.MenuProc ~ {
effects: Wraps around primarySelection a template for an expression type
ReplaceOrWrap[clientData: clientData, replace: FALSE];
};
GetOpClassName: PROC [opFamilyName: ATOM] RETURNS [opClassName: ATOMNIL] ~ {
selection: INT ← 0;
opNames: LIST OF ATOM ← MathDB.OpFamilyNames[opFamilyName];
selection ← PopUpSelection.Request[
header: Rope.Cat["Choose ", Convert.RopeFromAtom[opFamilyName], " Op"],
choice: MathDB.DescriptionsFromNames[opNames]
];
IF (selection < 1) THEN RETURN; -- no selection or timeout
opClassName ← NARROW[GetPopUpMenuAtom[selection, opNames] ];
};
ReplaceOrWrap: PROC [clientData: REF ANY, replace: BOOL] ~ {
effects: Replaces or wraps the active Primary selection with a template for an Operator chosen from a pop-up menus. Returns without action if errors occur.
selection: INT ← 0;
opFamiliesNames: LIST OF ATOM ← MathDB.OpFamiliesNames[];
opClassName: ATOM;
opFamilyName: ATOM;
ok: BOOLTRUE;
primaryViewer: Viewer ← NIL;
primaryExpr: DisplayExpr ← NIL;
s: ExprViewerData ← NARROW[clientData]; -- check primary selection exists
[ok, primaryViewer, primaryExpr] ← CheckSelection[$primary, s.exprViewer];
IF ~ok THEN RETURN;
selection ← PopUpSelection.Request[header: "Choose Operator Type", choice: MathDB.RopesFromAtoms[opFamiliesNames] ];
IF (selection < 1) THEN RETURN; -- no selection or timeout
opFamilyName ← NARROW[GetPopUpMenuAtom[selection, opFamiliesNames] ];
opClassName ← GetOpClassName[opFamilyName];
IF opClassName = NIL THEN RETURN; -- no selection or timeout
IF replace THEN
ReplaceWithTemplate[opClassName, primaryViewer, primaryExpr, TRUE]
ELSE
WrapTemplateIntoViewer[opClassName, primaryViewer, primaryExpr, TRUE];
};
UnaryFunction: PROC [name: ATOM, arg: DisplayExpr ← NIL] RETURNS [DisplayExpr] ~ {
effects: Creates a unary function template with $f Argument set to name. If arg#NIL, then sets $arg1 Argument to a copy of arg (arg itself is NOT put into replacement, since to do so would imply altering its parent pointer).
nameExpr: EXPR ← MathConstructors.MakeVariable[Convert.RopeFromAtom[from: name, quote: FALSE] ];
argExpr: EXPRIF arg#NIL THEN MathDisplayExpr.ExprFromDisplayExpr[arg] ELSE MathConstructors.MakePlaceHolder[];
funcExpr: EXPR ← MathExpr.MakeCompoundExpr[$unaryFunction, LIST[[$f, nameExpr], [$arg1, argExpr] ] ];
RETURN[MathDisplayExpr.DisplayExprFromExpr[funcExpr] ];
};
MakeTemplate: PROC [class: ATOM, blink: BOOLFALSE] RETURNS[replacement, hotArg: DisplayExpr ← NIL]~ {
effects: Create a template for a class expression, or a unary function of that name if class not found.
If this template class has no hot Argument, then hotArg ← NIL is returned.
local declarations
exprClass: CompoundClass;
argExprs: LIST OF MathExpr.TaggedMathExpr ← NIL;
hotTag: ATOM; -- tag of "hot" argument
ok: BOOLTRUE;
lookup classname in database; make unaryFunction if not found
exprClass ← MathDB.LookupCompoundClass[class ! MathDB.notFound => {
IF blink THEN {
MessageWindow.Append["Template Not found", TRUE];
MessageWindow.Blink[];
};
replacement ← UnaryFunction[class];
hotTag ← $arg1;
ok ← FALSE;
CONTINUE};
];
create expressions for each argument to make LIST OF TaggedMathExpr
IF ok THEN {
FOR l: LIST OF Argument ← exprClass.arguments, l.rest UNTIL l = NIL DO
FOR aliases: LIST OF ATOM ← l.first.aliases, aliases.rest UNTIL aliases = NIL DO
IF aliases.first = $aliasHot THEN {hotTag ← l.first.name; EXIT};
ENDLOOP;
argExprs ← CONS[[l.first.name, MathConstructors.MakePlaceHolder[]], argExprs];
ENDLOOP;
replacement ← MathDisplayExpr.DisplayExprFromExpr[MathExpr.MakeCompoundExpr[class, argExprs]]
};
get hook onto hot arg
FOR l: LIST OF DisplayExpr ← replacement.GetSubExprs[], l.rest UNTIL l = NIL DO
IF l.first.Tag[] = hotTag THEN {
hotArg ← l.first;
EXIT; -- break out of FOR loop
};
ENDLOOP;
};
ReplaceWithTemplate: PROC [class: ATOM, viewer: Viewer, expr: DisplayExpr, blink: BOOLFALSE] ~ {
requires: viewer contains expr
modifies: viewer.data
effects: Replaces expr in viewer with a template for a class expression, or a unary function of that name if class not found.
local declarations
replacement, hotArg: DisplayExpr;
[replacement, hotArg] ← MakeTemplate[class, blink];
replace expr in viewer with replacement
ReplaceInViewer[viewer, expr, replacement];
ViewExprOps.UnSelect[$primary];
if possible, select hotArg as primary selection, else select whole thing
IF hotArg # NIL THEN
ViewExprOps.Select[$primary, viewer, hotArg]
ELSE ViewExprOps.Select[$primary, viewer, replacement];
repaint viewer to reflect replacement
RepaintViewer[viewer];
};
WrapTemplate: PROC [class: ATOM, expr: DisplayExpr, blink: BOOLFALSE] RETURNS[replacement, selectableSibling, wrapArg: DisplayExpr] ~ {
effects: Wraps a template for an expression of compound class "class" around expr.
expr itself is NOT put into replacement (since to do so would imply altering its parent pointer), but a copy of it. wrapArg is (a pointer to) this copy.
If no selectable sibling (of wrapArg) exists, then selectableSibling ← NIL is returned.
exprClass: CompoundClass; -- class data associated with class
argExprs: LIST OF MathExpr.TaggedMathExpr ← NIL;
hotTag: ATOM; -- tag of "hot" argument
ok: BOOLTRUE;
replacement ← selectableSibling ← wrapArg ← NIL;
lookup classname in database; wrap unaryFunction if not found
exprClass ← MathDB.LookupCompoundClass[class ! MathDB.notFound => {
IF blink THEN {
MessageWindow.Append["Template Not found", TRUE];
MessageWindow.Blink[];
};
replacement ← UnaryFunction[class, expr];
hotTag ← $f; -- so selectableSibling will be $arg1
ok ← FALSE;
CONTINUE };
];
create expressions for each argument to make LIST OF TaggedMathExpr
IF ok THEN {
FOR l: LIST OF Argument ← exprClass.arguments, l.rest UNTIL l = NIL DO
hot: BOOLFALSE;
FOR aliases: LIST OF ATOM ← l.first.aliases, aliases.rest UNTIL aliases = NIL DO
IF aliases.first = $aliasHot THEN {hotTag ← l.first.name; hot ← TRUE; EXIT};
ENDLOOP;
IF hot AND (expr.Class[] # $placeholder) THEN {
argExprs ← CONS[[l.first.name, MathDisplayExpr.ExprFromDisplayExpr[expr]], argExprs];
}
ELSE {
argExprs ← CONS[[l.first.name, MathConstructors.MakePlaceHolder[]], argExprs];
};
ENDLOOP;
replacement ← MathDisplayExpr.DisplayExprFromExpr[MathExpr.MakeCompoundExpr[class, argExprs]];
};
find selectable sibling, if any.
FOR l: LIST OF DisplayExpr ← replacement.GetSubExprs[], l.rest UNTIL l = NIL DO
IF l.first.Tag[] = hotTag THEN {
wrapArg ← l.first;
selectableSibling ← l.first.SelectableSibling[! MathDisplayExpr.noSelection => CONTINUE];
EXIT; -- break out of FOR loop
};
ENDLOOP;
};
WrapTemplateIntoViewer: PROC [class: ATOM, viewer: Viewer, expr: DisplayExpr, blink: BOOLFALSE] ~ {
requires: viewer contains expr
modifies: viewer
effects: Replaces expr in viewer with a template for a class expression, or a unary function of that name if class not found.
The primary selection is changed to be a sibling of the "hot" argument.
replacement, selectableSibling, wrapArg: DisplayExpr;
[replacement, selectableSibling, wrapArg] ← WrapTemplate[class, expr, blink];
replace expr in viewer with replacement
ReplaceInViewer[viewer, expr, replacement];
ViewExprOps.UnSelect[$primary];
if possible, select sibling as primary selection, else select what got wrapped
IF selectableSibling # NIL THEN
ViewExprOps.Select[$primary, viewer, selectableSibling]
ELSE ViewExprOps.Select[$primary, viewer, wrapArg];
RepaintViewer[viewer];
};
Keyboard-driven Expression Editing
PlaceHolder: PROC [] RETURNS [DisplayExpr] ~ {
RETURN[MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakePlaceHolder[] ] ];
};
ParseActionFromChar: PROC[c: CHAR] ~ {
modifies: kbBuffer, message window, $primary and $keyboard selections
effects: Parses c w.r.t contents of kbBuffer.
Updates kbBuffer, message window, and $keyboard selection (viewer & expr).
assumes UndoAction will not occur, hence no viewer arg needed
local declarations
action: Parser.ParseAction;
character parsing only meaningful if either a primary or KB selection active
IF ~ViewExprOps.Active[$primary] AND ~ViewExprOps.Active[$keyboard] THEN {
msg: ROPE ← "Need either a Primary or a Keyboard selection";
MessageWindow.Append[msg, TRUE];
MessageWindow.Blink[];
RETURN;
};
parse character, determine action
[kbBuffer, action] ← Parser.ParseKBChar[c, kbBuffer, ViewExprOps.Active[$primary], ViewExprOps.Active[$keyboard] ];
perform parse action
WITH action SELECT FROM
r: REF Parser.ReplaceAction => {
local declarations
selectedViewer: Viewer ← NIL;
selectedExpr, replacement: DisplayExpr ← NIL;
ok: BOOLTRUE;
[selectedViewer, selectedExpr] ← ViewExprOps.GetSelection[r.oldSelection ! ViewExprOps.noSelection => {ok ← FALSE; CONTINUE}];
IF ok THEN {
SELECT r.replacementType FROM
integer => {
replacement ← MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakeInt[r.fromRope]];
};
real => {
replacement ← MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakeReal[Convert.RealFromRope[r.fromRope]]];
};
variable, templateName => {
replacement ← MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakeVariable[r.fromRope]];
};
ENDCASE; -- do nothing here for template
SELECT r.replacementType FROM
integer, real, variable, templateName => {
ReplaceInViewer[selectedViewer, selectedExpr, replacement]; -- do the replace
ViewExprOps.UnSelect[r.oldSelection];
ViewExprOps.Select[r.newSelection, selectedViewer, replacement]; -- will repaint viewer to reflect change (i.e. the replacement)
};
template => {
ReplaceWithTemplate[Convert.AtomFromRope[r.fromRope], selectedViewer, selectedExpr];
};
ENDCASE => ERROR;
};
}; -- end of "replace Parse action choice"
w: REF Parser.WrapAction => {
local declarations
selectedViewer: Viewer ← NIL;
selectedExpr: DisplayExpr ← NIL;
ok: BOOLTRUE;
[selectedViewer, selectedExpr] ← ViewExprOps.GetSelection[w.selection ! ViewExprOps.noSelection => {ok ← FALSE; CONTINUE}];
IF ok THEN WrapTemplateIntoViewer[w.class, selectedViewer, selectedExpr];
ResetKBBuffer[];
}; -- end of "wrap Parse action choice"
b: REF Parser.BeginMultiCharTemplateAction => {
selectedViewer: Viewer ← NIL;
selectedExpr, replacement: DisplayExpr ← NIL;
ok: BOOLTRUE;
[selectedViewer, selectedExpr] ← ViewExprOps.GetSelection[b.oldSelection ! ViewExprOps.noSelection => {ok ← FALSE; CONTINUE}];
IF ~ok THEN RETURN;
kbBuffer ← [type: templateName, data: "", savedWrapArg: selectedExpr]; -- initialize kbBuffer; data = "" since delimiter is not part of name
replacement ← MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakeVariable["?"]];
ReplaceInViewer[selectedViewer, selectedExpr, replacement]; -- display "?"
ViewExprOps.UnSelect[b.oldSelection];
ViewExprOps.Select[$keyboard, selectedViewer, replacement];
};
f: REF Parser.FinishMultiCharTemplateAction => {
local declarations
selectedViewer: Viewer ← NIL;
selectedExpr, replacement: DisplayExpr ← NIL;
ok: BOOLTRUE;
[selectedViewer, selectedExpr] ← ViewExprOps.GetSelection[$keyboard ! ViewExprOps.noSelection => {ok ← FALSE; CONTINUE}];
IF ~ok THEN ERROR;
ReplaceInViewer[selectedViewer, selectedExpr, kbBuffer.savedWrapArg]; -- replace current KB selection with savedWrapArg, giving us a (hook onto a) placeholder we will replace with the completed template
WrapTemplateIntoViewer[f.class, selectedViewer, kbBuffer.savedWrapArg]; -- do the wrap
ResetKBBuffer[];
};
u: REF Parser.UndoAction => UndoViewer[viewer];
n: REF Parser.NoAction => NULL; -- do nothing; no action
ENDCASE => ERROR;
};
HandleUserAction: PROC [action: REF, viewer: Viewer ← NIL] ~ {
WITH action SELECT FROM
refC: REF CHAR => SELECT refC^ FROM
'\010 => IF viewer#NIL THEN UndoViewer[viewer] ELSE RETURN; -- pick this one up here since relates to Viewers
ENDCASE => ParseActionFromChar[refC^];
ENDCASE => {
flavor: ATOM;
selectedExpr: DisplayExpr ← NIL;
selectedViewer: Viewer ← NIL;
ok: BOOL;
SELECT action FROM
$PrimaryParentSelect, $CopyParentSelect, $MoveParentSelect, $PrimaryChildSelect, $PrimarySiblingSelect => {
SELECT action FROM
$PrimaryParentSelect, $PrimaryChildSelect, $PrimarySiblingSelect => flavor ← $primary;
$CopyParentSelect => flavor ← $copy;
$MoveParentSelect => flavor ← $move;
ENDCASE;
[ok, selectedViewer, selectedExpr] ← CheckSelection[flavor];
IF ~ok THEN RETURN;
SELECT action FROM
$PrimaryParentSelect, $CopyParentSelect, $MoveParentSelect => {
extend selection to its parent
ViewExprOps.Select[flavor, selectedViewer, MathDisplayExpr.SelectableParent[selectedExpr ! MathDisplayExpr.noSelection => {CONTINUE}]];
};
$PrimaryChildSelect => {
change active primary or keyboard selection to its child as a primary selection
ViewExprOps.Select[$primary, selectedViewer, MathDisplayExpr.SelectableChild[selectedExpr ! MathDisplayExpr.noSelection => {CONTINUE}]];
};
$PrimarySiblingSelect => {
Change active primary or keyboard selection to a sibling as primary selection.
Alters selectedViewer.displayExpr if function extension hack happens.
sibling: DisplayExpr;
state: ExprViewerData;
ok: BOOLTRUE;
sibling ← MathDisplayExpr.SelectableSibling[selectedExpr ! MathDisplayExpr.noSelection => {ok ← FALSE; CONTINUE}];
IF ok THEN {
state ← NARROW[selectedViewer.data]; -- get current state
state.displayBox ← state.displayExpr.Format[normal]; -- reformat in case function hack happened
ViewExprOps.Select[$primary, selectedViewer, sibling];
};
};
ENDCASE => ERROR;
};
$PrimaryDelete => {
IF ViewExprOps.Active[$primary] THEN
DeleteSelection[$primary]
ELSE
DeleteSelection[$keyboard];
};
$Undo => UndoViewer[viewer];
$SelectEntire => SelectEntireViewer[viewer, $primary];
$SelectionToPrimary => {
convert active keyboard selection to primary selection
ChangeSelectionFlavor[$keyboard, $primary];
};
$DoPendingCopy => {
IF ViewExprOps.Active[$copy] THEN CopySecondaryToPrimary[];
};
$SetSwap => {
setSwap ← TRUE;
};
$DoPendingMove => {
IF ViewExprOps.Active[$move] THEN
IF setSwap THEN SwapSecondaryAndPrimary[]
ELSE MoveSecondaryToPrimary[];
setSwap ← FALSE;
};
$EvalPrimaryInPlace => {
primaryViewer: Viewer;
primaryDisplayExpr, evalDisplayExpr: DisplayExpr;
[primaryViewer, primaryDisplayExpr, evalDisplayExpr,] ← EvalSelection[$primary];
ReplaceInViewer[primaryViewer, primaryDisplayExpr, evalDisplayExpr];
RepaintViewer[primaryViewer];
};
ENDCASE => RETURN; -- take no action given unrecognized TIP actions
};
};
ParseActionFromCharNoViewer: PROC[c: CHAR, outerDisplayExpr, primarySelection, keyboardSelection: DisplayExpr] RETURNS[newOuter, newPrimary, newKeyboard: DisplayExpr] ~ {
modifies: kbBuffer
effects: Parses c w.r.t contents of kbBuffer.
Updates kbBuffer, message window, and $keyboard selection (viewer & expr).
assumes Parser.UndoAction will not occur, hence no viewer arg needed
considers that selection#NIL is "equivalent" to ViewExprOps.Active[selectionFlavor], e.g. you "UnSelect" a selection by setting it ← NIL.
Assumes outerDisplayExpr contains primarySelection and keyboardSelection
local declarations
action: Parser.ParseAction;
Initializations
newOuter ← outerDisplayExpr;
newPrimary ← primarySelection;
newKeyboard ← keyboardSelection;
parse character, determine action
[kbBuffer, action] ← Parser.ParseKBChar[c, kbBuffer, primarySelection#NIL, keyboardSelection#NIL ];
perform parse action
WITH action SELECT FROM
r: REF Parser.ReplaceAction => {
local declarations
selectedExpr, replacement, hotArg: DisplayExpr ← NIL;
selectedExpr ← SELECT r.oldSelection FROM
$primary => primarySelection,
$keyboard => keyboardSelection,
ENDCASE => ERROR;
IF selectedExpr=NIL THEN RETURN[outerDisplayExpr, primarySelection, keyboardSelection];
SELECT r.replacementType FROM
integer => {
replacement ← MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakeInt[r.fromRope]];
};
real => {
replacement ← MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakeReal[Convert.RealFromRope[r.fromRope]]];
};
variable, templateName => {
replacement ← MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakeVariable[r.fromRope]];
};
ENDCASE; -- do nothing here for template
SELECT r.replacementType FROM
integer, real, variable, templateName => {
newOuter ← MathDisplayExpr.Replace[outerDisplayExpr, selectedExpr, replacement];
SELECT r.newSelection FROM
$primary => {newPrimary ← replacement; newKeyboard ← NIL};
$keyboard => {newKeyboard ← replacement; newPrimary ← NIL};
ENDCASE => ERROR;
};
template => {
ok: BOOLTRUE;
wrapParen: BOOL;
selectableSibling, wrapArg, parent: DisplayExpr;
parentClass: ATOM;
templateClass: ATOM ← Convert.AtomFromRope[r.fromRope];
parent ← MathDisplayExpr.SelectableParent[selectedExpr ! MathDisplayExpr.noSelection => {ok ← FALSE; CONTINUE} ];
IF ok THEN parentClass ← MathDisplayExpr.Class[parent] ELSE parentClass ← $none;
[replacement, hotArg] ← MakeTemplate[templateClass];
*** Begin parenthesis hack 7/15/87
wrapParen ← FALSE;
SELECT parentClass FROM
$product => SELECT templateClass FROM
$sum, $difference => wrapParen ← TRUE;
ENDCASE;
$pow => SELECT templateClass FROM
$product, $sum, $difference => wrapParen ← TRUE;
ENDCASE;
ENDCASE;
IF wrapParen THEN {
[replacement, selectableSibling, wrapArg] ← WrapTemplate[$paren, replacement]; -- wrapArg is now a copy of (previous) replacement
hotArg ← MathDisplayExpr.SelectableChild[wrapArg]; -- assumes first Argument is hot;
};
*** End parenthesis hack 7/15/87
*** Begin a+-b hack 7/16/87
IF parentClass = $sum AND templateClass = $negation AND MathDisplayExpr.Tag[selectedExpr]=$augend THEN {
[replacement, selectableSibling, wrapArg] ← WrapTemplate[$difference, MathDisplayExpr.SelectableSibling[selectedExpr] ];
newOuter ← MathDisplayExpr.Replace[outerDisplayExpr, parent, replacement];
newPrimary ← selectableSibling;
newKeyboard ← NIL; -- since we have a nonNIL newPrimary
ResetKBBuffer[];
ignoreNextRightBracket ← TRUE; -- ugly hack global var
RETURN;
};
*** End a+-b hack
newOuter ← MathDisplayExpr.Replace[outerDisplayExpr, selectedExpr, replacement];
if possible, select hotArg as primary selection, else select whole thing
IF hotArg#NIL THEN newPrimary ← hotArg ELSE newPrimary ← replacement;
newKeyboard ← NIL; -- since we have a nonNIL newPrimary
ResetKBBuffer[];
};
ENDCASE => ERROR;
}; -- end of "replace Parse action choice"
w: REF Parser.WrapAction => {
local declarations
selectedExpr, replacement, selectableSibling, wrapArg: DisplayExpr ← NIL;
selectedExpr ← SELECT w.selection FROM
$primary => primarySelection,
$keyboard => keyboardSelection,
ENDCASE => ERROR;
IF selectedExpr=NIL THEN RETURN[outerDisplayExpr, primarySelection, keyboardSelection];
[replacement, selectableSibling, wrapArg] ← WrapTemplate[w.class, selectedExpr];
newOuter ← MathDisplayExpr.Replace[outerDisplayExpr, selectedExpr, replacement];
if possible, select sibling as primary selection, else select what got wrapped
IF selectableSibling # NIL THEN
newPrimary ← selectableSibling ELSE newPrimary ← wrapArg;
newKeyboard ← NIL; -- since we have a nonNIL newPrimary
ResetKBBuffer[];
}; -- end of "wrap Parse action choice"
b: REF Parser.BeginMultiCharTemplateAction => {
selectedExpr, replacement: DisplayExpr ← NIL;
selectedExpr ← SELECT b.oldSelection FROM
$primary => primarySelection,
$keyboard => keyboardSelection,
ENDCASE => ERROR;
IF selectedExpr=NIL THEN RETURN[outerDisplayExpr, primarySelection, keyboardSelection];
kbBuffer ← [type: templateName, data: "", savedWrapArg: selectedExpr]; -- initialize kbBuffer; data = "" since delimiter is not part of name
replacement ← MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakeVariable["?"]];
newOuter ← MathDisplayExpr.Replace[outerDisplayExpr, selectedExpr, replacement];
newKeyboard ← replacement; -- active KB => Primary selection inactive
newPrimary ← NIL;
};
f: REF Parser.FinishMultiCharTemplateAction => {
local declarations
replacement, selectableSibling, wrapArg: DisplayExpr;
selectedExpr: DisplayExpr ← keyboardSelection;
IF selectedExpr=NIL THEN RETURN[outerDisplayExpr, primarySelection, keyboardSelection];
[replacement, selectableSibling, wrapArg] ← WrapTemplate[f.class, kbBuffer.savedWrapArg]; -- do the wrap of savedWrapArg
newOuter ← MathDisplayExpr.Replace[outerDisplayExpr, selectedExpr, replacement]; -- replace current KB selection with completed template
if possible, select sibling as primary selection, else select what got wrapped
IF selectableSibling # NIL THEN newPrimary ← selectableSibling ELSE newPrimary ← wrapArg;
newKeyboard ← NIL; -- since there's an active Primary selection
ResetKBBuffer[];
};
n: REF Parser.NoAction => NULL; -- do nothing; no action
ENDCASE => ERROR;
};
HandleUserActionNoViewer: PROC [action: REF, outerDisplayExpr, primarySelection, keyboardSelection: DisplayExpr] RETURNS[newOuter, newPrimary, newKeyboard: DisplayExpr] ~ {
Assumes outerDisplayExpr contains primarySelection and keyboardSelection
WITH action SELECT FROM
refC: REF CHAR => SELECT refC^ FROM
'\010 => NULL; -- ^H (UndoViewer) meaningless
ENDCASE => {
[newOuter, newPrimary, newKeyboard] ← ParseActionFromCharNoViewer[refC^, outerDisplayExpr, primarySelection, keyboardSelection];
RETURN[newOuter, newPrimary, newKeyboard];
};
ENDCASE => {
selection: DisplayExpr ← IF primarySelection#NIL THEN primarySelection ELSE keyboardSelection; -- use KB as Primary if need be
SELECT action FROM
$PrimaryParentSelect => {
extend selection to its parent
parent: DisplayExpr ← selection;
parent ← MathDisplayExpr.SelectableParent[selection ! MathDisplayExpr.noSelection => {CONTINUE}];
RETURN[outerDisplayExpr, parent, NIL]; -- making a Primary => KB ← NIL
};
$PrimaryChildSelect => {
change active primary or keyboard selection to its child as a primary selection
child: DisplayExpr ← selection;
child ← MathDisplayExpr.SelectableChild[selection ! MathDisplayExpr.noSelection => {CONTINUE}];
RETURN[outerDisplayExpr, child, NIL];
};
$PrimarySiblingSelect => {
Change active primary or keyboard selection to a sibling as primary selection.
Alters outerDisplayExpr if function extension hack happens.
sibling: DisplayExpr ← selection;
sibling ← MathDisplayExpr.SelectableSibling[selection ! MathDisplayExpr.noSelection => {CONTINUE}];
RETURN[outerDisplayExpr, sibling, NIL];
};
$PrimaryDelete => { -- should be doable in here
$EvalPrimaryInPlace => { -- -- should be doable in here
ENDCASE => RETURN; -- take no action given unrecognized TIP actions
};
};
DisplayExprFromRope: PROC [rope: ROPE] RETURNS[replacement: DisplayExpr]~ {
action: REF;
outerDisplayExpr: DisplayExpr ← PlaceHolder[];
primarySelection: DisplayExpr ← outerDisplayExpr;
keyboardSelection: DisplayExpr ← NIL; -- No KB selection initially
ResetKBBuffer[];
FOR i: INT IN [0..Rope.Length[rope]) DO
c: CHAR ← Rope.Fetch[rope, i];
SELECT c FROM
', => action ← $PrimarySiblingSelect;
'] => action ← $PrimaryParentSelect;
ENDCASE => action ← NEW[CHAR ← c];
IF c#'] OR ~ignoreNextRightBracket THEN
[outerDisplayExpr, primarySelection, keyboardSelection] ← HandleUserActionNoViewer[action, outerDisplayExpr, primarySelection, keyboardSelection]; -- *** a+-b hack 7/16/87
IF c='] AND ignoreNextRightBracket THEN ignoreNextRightBracket ← FALSE;
ENDLOOP;
RETURN[outerDisplayExpr];
};
PrimarySelectionFromRope: PROC [rope: ROPE ] ~ {
Replaces primary selection with the result of parsing a Rope
okPrimary: BOOL;
selectedViewer: Viewer ← NIL;
primarySelection, replacement: DisplayExpr;
[okPrimary, selectedViewer, primarySelection] ← CheckSelection[$primary];
IF ~okPrimary THEN RETURN;
replacement ← DisplayExprFromRope[rope];
ReplaceInViewer[selectedViewer, primarySelection, replacement];
RepaintViewer[selectedViewer];
};
Domain (Structure) management
SetWorkingDomain: Buttons.ButtonProc = {
caminoItem: CaminoItem ← NARROW[clientData]; -- get our data
opNames: LIST OF ROPELIST["Bools", "Colors", "FormulaOperators", "Integers", "Rationals", "Reals", "Complexes", "Matrices", "Polynomials", "Formulas", "RealAlgebraicNumbers", "ExtensionField", "Points", "Sequences", "SamplePoints", "CoveringSets", "Cells", "Cads"];
opNames: LIST OF ROPELIST["Expressions", "Variables", "Bools", "Integers", "Rationals", "Reals", "Complexes", "SingleSet", "FamilyOfSets", "Sequences", "Vectors", "Matrices", "Polynomials"];
domain: Object;
selection: INT ← 0;
oneToTen: LIST OF ROPELIST["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"];
constants
expressions: INT = 1;
variables: INT = 2;
bools: INT = 3;
integers: INT = 4;
rationals: INT = 5;
reals: INT = 6;
complexes: INT = 7;
singleSet: INT = 8;
familyOfSets: INT = 9;
sequences: INT = 10;
vectors: INT = 11;
matrices: INT = 12;
polynomials: INT = 13;
Do pop-up menu
selection ← PopUpSelection.Request[header: "Set Domain", choice: opNames];
SELECT selection FROM
< 1 => RETURN; -- no selection, cancel, or timeout
= expressions => domain ← Expressions.MeddleExprs;
= variables => domain ← Variables.Variables;
= bools => domain ← Bools.Bools;
= integers => domain ← Ints.Ints;
= rationals => domain ← BigRats.BigRats;
= reals => domain ← Reals.Reals;
= complexes => domain ← Complexes.Complexes;
= singleSet => {
underlyingSet: Object ← Sets.FamilyOfSetsFromRope[ViewerTools.GetContents[caminoItem.scratchPadViewer], caminoItem.workingDomain];
domain ← Sets.MakeSingleSetStructure[underlyingSet];
};
= familyOfSets => {
domain ← Sets.MakeFamilyOfSetsStructure[caminoItem.workingDomain];
};
= sequences => {
domain ← SEQ.MakeSequenceStructure[caminoItem.workingDomain];
};
= vectors => {
dimension: NAT ← 0;
dimension ← PopUpSelection.Request[header: "Dimension", choice: oneToTen];
IF (dimension < 1) THEN RETURN; -- no selection or timeout
domain ← VEC.MakeVectorStructure[caminoItem.workingDomain, dimension];
};
= matrices => {
nRows, nCols: INT ← 0;
nRows ← PopUpSelection.Request[header: "# Rows", choice: oneToTen];
IF (nRows < 1) THEN RETURN; -- no selection or timeout
nCols ← PopUpSelection.Request[header: "# Cols", choice: oneToTen];
IF (nCols < 1) THEN RETURN; -- no selection or timeout
domain ← MAT.MakeMatrixStructure[caminoItem.workingDomain, nRows, nCols];
};
= polynomials => {
varSeq: VariableSequences.VariableSequence ← SEQ.FromRope[ViewerTools.GetContents[caminoItem.scratchPadViewer], VariableSequences.VariableSequences];
domain ← POL.MakePolynomialStructure[caminoItem.workingDomain, varSeq];
};
ENDCASE;
Associate this domain with this Camino item
caminoItem.workingDomain ← domain;
Labels.Set[caminoItem.workingDomainViewer, domain.name ];
};
Evaluation of Meddle and Tioga selections
ObjectFromSelection: PROC[flavor: ATOM, thisViewer: Viewer ← NIL] RETURNS [ok: BOOLTRUE, selectionViewer: Viewer, selectionExpr: DisplayExpr, object: Object] ~ {
expr: EXPR;
[ok, selectionViewer, selectionExpr] ← CheckSelection[flavor, thisViewer];
IF NOT ok THEN RETURN[FALSE, NIL, NIL, NIL];
expr ← MathDisplayExpr.ExprFromDisplayExpr[selectionExpr];
object ← Evaluator.Eval[expr];
RETURN[TRUE, selectionViewer, selectionExpr, object];
};
EvalPrimaryInPlace: Menus.MenuProc ~ {
caminoItem: CaminoItem ← NARROW[clientData];
primaryViewer: Viewer;
primaryDisplayExpr, evalDisplayExpr: DisplayExpr;
evalObjectStructure: ROPE;
s: ExprViewerData ← NARROW[caminoItem.exprViewer.data];
[primaryViewer, primaryDisplayExpr, evalDisplayExpr, evalObjectStructure] ← EvalSelection[$primary, s.exprViewer];
ReplaceInViewer[primaryViewer, primaryDisplayExpr, evalDisplayExpr];
Labels.Set[caminoItem.objectDomainViewer, evalObjectStructure]; -- set ObjectDomain viewer of caminoItem to evalObjectStructure
RepaintViewer[primaryViewer];
};
EvalSelection: PROC [flavor: ATOM, thisViewer: Viewer ← NIL] RETURNS [selectionViewer: Viewer, selectionExpr, result: DisplayExpr, structureName: ROPE] ~ {
ok: BOOLTRUE;
evalExpr: EXPR;
evalObject, evalObjectStructure: AC.Object;
[ok, selectionViewer, selectionExpr, evalObject] ← ObjectFromSelection[flavor, thisViewer];
IF NOT ok THEN RETURN[selectionViewer, selectionExpr, NIL, NIL];
evalObjectStructure ← evalObject.class;
evalExpr ← NARROW[AC.ApplyLkpNoRecastRef[$toExpr, evalObjectStructure, LIST[evalObject] ] ];
RETURN[
selectionViewer,
selectionExpr,
MathDisplayExpr.DisplayExprFromExpr[evalExpr],
NARROW[AC.ApplyNoLkpNoRecastRef[AC.LookupMethodInStructure[$shortPrintName, evalObjectStructure], LIST[evalObjectStructure] ] ]
];
};
RopeFromFile: PROC [filename: ROPE] RETURNS [ROPE] ~ {
stream: IO.STREAMFS.StreamOpen[filename, $read];
rope: ROPE ← "";
c: CHAR ← stream.GetChar[]; -- toss first newline
WHILE NOT stream.EndOf[] DO
c ← stream.GetChar[];
IF ~stream.EndOf[] THEN rope ← rope.Cat[Rope.FromChar[c] ]; ENDLOOP; -- toss last newline
RETURN[rope];
};
InsertArgInScript: PROC [flavorRope: ROPE, arg: ROPE] ~ {
position: INT;
script: ROPE ← RopeFromFile[Rope.Cat[flavorRope, "Script"] ];
out: IO.STREAMFS.StreamOpen[fileName: Rope.Cat[flavorRope, "In"], accessOptions: $create, wDir: FSExtras.GetWDir[] ]; -- also could use CommandTool.FileNames interface; in any event, FSExtras.GetWDir seems to just be returning /// as WD, i.e. trivial effect. Probably result of call not coming from a Commander.CommandProc
position ← Rope.Find[script, "#1"]; -- all scripts should denote arg position as '#1'
script ← Rope.Replace[base: script, start: position, len: Rope.Length["#1"], with: arg];
out.PutRope[script];
out.Close[];
};
DoAlgebra: Menus.MenuProc ~ {
caminoItem: CaminoItem ← NARROW[clientData];
s: ExprViewerData ← NARROW[caminoItem.exprViewer.data];
v: ViewerTools.Viewer;
ok: BOOL;
primaryViewer: Viewer ← NIL;
primaryExpr: DisplayExpr ← NIL;
flavor: ATOMSELECT mouseButton FROM
red => $SMP,
yellow => $Reduce,
blue => $Reduce,
ENDCASE => ERROR;
flavorRope: ROPE = Convert.RopeFromAtom[flavor, FALSE];
algebraRope: ROPE;
errmsg: ROPE;
outputFileName: ROPE;
[ok, primaryViewer, primaryExpr] ← CheckSelection[$primary];
IF ~ok THEN RETURN;
algebraRope ← MathDisplayExpr.ASRopeFromDisplayExpr[primaryExpr, flavor];
InsertArgInScript[flavorRope, algebraRope];
[outputFileName, errmsg] ← RemoteAlgebra.DoRemoteAlgebra[flavorRope];
IF errmsg#NIL THEN {
MessageWindow.Append[errmsg, TRUE];
MessageWindow.Blink[];
RETURN;
};
PrimarySelectionFromRope[RopeFromFile[outputFileName] ];
WHILE NOT outputStream.EndOf[] DO
outputRope ← outputRope.Cat[Rope.FromChar[outputStream.GetChar[] ] ];
ENDLOOP;
v ← ViewerTools.MakeNewTextViewer[info: [name: Rope.Cat["Algebra Result Rope for ", s.exprViewer.name], iconic: FALSE] ];
ViewerTools.SetContents[v, outputRope];
};
EvalTiogaInPlace: Menus.MenuProc ~ {
effects: Eval Tioga selection in place.
caminoItem: CaminoItem ← NARROW[clientData];
local declarations
ok: BOOLTRUE;
evalExpr: EXPR;
evalObject, evalObjectStructure: AC.Object;
toExprMethod: AC.Method;
linearExpr: ROPE;
exprVal: EXPRNIL;
location: TiogaOps.Location ← TiogaOps.GetSelection[primary].start;
selection: TextEdit.RefTextNode ← location.node;
exprRope: ROPENARROW[TextEdit.GetCharProp[selection, location.where, $MeddleExpr]];
exprPtSize: ROPENARROW[TextEdit.GetCharProp[selection, location.where, $MeddlePtSize]];
exprVal ← MathExpr.ExprFromRope[ StripHeader[exprRope] ! MathExpr.parseError => {ok ← FALSE; CONTINUE}];
evalObject ← Evaluator.Eval[exprVal];
evalObjectStructure ← evalObject.class;
toExprMethod ← AC.LookupMethodInStructure[$toExpr, evalObjectStructure];
evalExpr ← NARROW[AC.ApplyNoLkpNoRecastRef[toExprMethod, LIST[evalObject] ] ];
linearExpr ← MathExpr.RopeFromExpr[evalExpr];
PlaceInTioga[caminoItem, linearExpr];
Labels.Set[caminoItem.objectDomainViewer, NARROW[AC.ApplyNoLkpNoRecastRef[AC.LookupMethodInStructure[$shortPrintName, evalObjectStructure], LIST[evalObjectStructure] ] ] ]; -- set ObjectDomain viewer of caminoItem to evalObjectStructure
};
Algebraic operations on Meddle selections
OperatePrimaryNew: Menus.MenuProc ~ {
caminoItem: CaminoItem ← NARROW[clientData];
OperatePrimarySelection[caminoItem, TRUE];
};
OperatePrimaryInPlace: Menus.MenuProc ~ {
caminoItem: CaminoItem ← NARROW[clientData];
OperatePrimarySelection[caminoItem, FALSE];
};
OperatePrimarySelection: PROC [caminoItem: CaminoItem, newItem: BOOLTRUE, sourceStructureForMethod: Object ← NIL] ~ {
opNames: LIST OF ROPE;
operators: LIST OF Method;
operator: Method;
choiceRope: ROPE;
refOps: LIST OF REFNIL;
selection: INT ← 0;
firstArg, secondArg: AC.Object ← NIL;
args, reCastArgs: LIST OF Object;
result: Object;
primaryExpr, copyExpr: DisplayExpr ← NIL;
primaryViewer, copyViewer: Viewer ← NIL;
ok: BOOL;
methodStructure: Object ← sourceStructureForMethod;
If no explicit Structure in which to look for method given, use Structure of Eval[primary selection].
IF methodStructure=NIL THEN {
[ok, primaryViewer, primaryExpr, firstArg] ← ObjectFromSelection[$primary];
IF NOT ok THEN RETURN;
methodStructure ← firstArg.class;
};
User selects an operator from methodStructure
[opNames, operators] ← AC.BuildClassOperators[methodStructure.class];
selection ← PopUpSelection.Request[header: "Choose operation", choice: opNames];
IF selection < 1 THEN RETURN; -- no selection or timeout
[operator, choiceRope] ← GetPopUpMenuMethod[selection, opNames, operators];
Check for operators that have non-Object arguments
IF Rope.Equal[choiceRope, "fromRope"] THEN {
textSelection: ROPE ← ViewerTools.GetSelectionContents[];
IF ~newItem THEN [ok, primaryViewer, primaryExpr] ← CheckSelection[$primary];
IF NOT ok THEN RETURN;
result ← AC.ApplyFromRopeMethod[operator, textSelection, methodStructure];
}
ELSE IF Rope.Equal[choiceRope, "canRecast"] OR Rope.Equal[choiceRope, "recast"] THEN {
[ok, primaryViewer, primaryExpr, firstArg] ← ObjectFromSelection[$primary];
IF NOT ok THEN RETURN;
args ← LIST[firstArg, methodStructure];
result ← AC.ApplyNoLkpNoRecastObject[operator, args];
}
Get Object args, recast them, and apply op
ELSE {
[ok, primaryViewer, primaryExpr, firstArg] ← ObjectFromSelection[$primary];
IF NOT ok THEN RETURN;
SELECT operator.type FROM
UnaryOp, UnaryPredicate, StructuredToGroundOp, ElementRankOp, CompareToZeroOp, BinaryMixedOp => args ← LIST[firstArg];
UnaryImbedOp => args ← LIST[firstArg, methodStructure]; -- diagonalMatrix is the only expected UnaryImbedOp; these are right args for it
BinaryOp, BinaryPredicate, BinaryCompareOp, TernaryMixedOp => {
ViewExprOps.UnSelect[$primary]; -- deselect now to prevent unwanted copy if shift key released (10/1/86 - needed?)
[ok, copyViewer, copyExpr, secondArg] ← ObjectFromSelection[$copy];
IF NOT ok THEN RETURN;
ViewExprOps.UnSelect[$copy];
args ← LIST[firstArg, secondArg];
};
ENDCASE => ERROR;
[ok, reCastArgs] ← AC.RecastArgs[operator, methodStructure, args];
IF ~ok THEN {
MessageWindow.Append["Unable to recast args", TRUE];
MessageWindow.Blink[];
RETURN
};
SELECT operator.type FROM
UnaryOp, UnaryPredicate, StructuredToGroundOp, ElementRankOp, BinaryOp, BinaryPredicate, UnaryImbedOp => result ← AC.ApplyNoLkpNoRecastObject[operator, reCastArgs];
BinaryMixedOp, TernaryMixedOp => { -- i.e. vector or sequence map op
groundStructure: Object;
groundOperator: Method;
IF ISTYPE[firstArg.class.data, SEQ.SequenceData] THEN
groundStructure ← NARROW[firstArg.class.data, SEQ.SequenceStructureData].elementStructure
ELSE IF ISTYPE[firstArg.data, VEC.VectorData] THEN
groundStructure ← NARROW[firstArg.class.data, VEC.VectorStructureData].coordinateStructure
ELSE RETURN;
[opNames, operators] ← AC.BuildClassOperators[groundStructure];
selection ← PopUpSelection.Request[header: "Choose operation", choice: opNames];
IF selection < 1 THEN RETURN; -- no selection or timeout
[groundOperator, choiceRope] ← GetPopUpMenuMethod[selection, opNames, operators];
result ← AC.ApplyMixedMethod[operator, reCastArgs, groundOperator];
};
CompareToZeroOp => {
sign: Basics.Comparison ← AC.ApplyCompareToZeroMethod[operator, reCastArgs.first];
SELECT sign FROM
less => result ← VARS.FromRope["less"];
equal => result ← VARS.FromRope["equal"];
greater => result ← VARS.FromRope["greater"];
ENDCASE => ERROR;
};
BinaryCompareOp => {
sign: Basics.Comparison ← AC.ApplyBinaryCompareMethod[operator, reCastArgs.first, reCastArgs.rest.first];
SELECT sign FROM
less => result ← VARS.FromRope["less"];
equal => result ← VARS.FromRope["equal"];
greater => result ← VARS.FromRope["greater"];
ENDCASE => ERROR;
};
ENDCASE => ERROR;
};
Figure out what to do with result
IF newItem THEN
SetResult[caminoItem: caminoItem, name: choiceRope, result: result, newItem: TRUE] -- will use SetViewerDisplayExpr since we are creating a new item
ELSE { -- this is similar to SetResult, should be bundled into a proc
resultStructure: Object ← result.class;
resultExpr: EXPRAC.ApplyLkpNoRecastExpr[$toExpr, resultStructure, LIST[result] ];
ReplaceInViewer[primaryViewer, primaryExpr, MathDisplayExpr.DisplayExprFromExpr[resultExpr] ];
Labels.Set[caminoItem.objectDomainViewer, NARROW[AC.ApplyNoLkpNoRecastRef[AC.LookupMethodInStructure[$shortPrintName, resultStructure], LIST[resultStructure] ] ] ];
RepaintViewer[primaryViewer];
};
}; -- End
OperateWorkingDomainNew: Menus.MenuProc ~ {
caminoItem: CaminoItem ← NARROW[clientData];
OperatePrimarySelection[caminoItem, TRUE, caminoItem.workingDomain];
};
OperateWorkingDomainInPlace: Menus.MenuProc ~ {
caminoItem: CaminoItem ← NARROW[clientData];
OperatePrimarySelection[caminoItem, FALSE, caminoItem.workingDomain];
};
SetResult: PROC [caminoItem: CaminoItem, name: ROPE, result: AC.Object, newItem: BOOLTRUE] ~ {
IF newItem THEN
[] ← CreateCaminoItem[name, result] -- ok not to go through SetViewerDisplayExpr filter since we are creating a new item
ELSE {
resultStructure: Object ← result.class;
resultExpr: EXPRAC.ApplyLkpNoRecastExpr[$toExpr, resultStructure, LIST[result] ];
resultDisplayExpr: DisplayExpr ← MathDisplayExpr.DisplayExprFromExpr[resultExpr];
SetViewerDisplayExpr[caminoItem.exprViewer, resultDisplayExpr];
caminoItem.name ← caminoItem.outer.name ← name;
Labels.Set[caminoItem.objectDomainViewer, NARROW[AC.ApplyNoLkpNoRecastRef[AC.LookupMethodInStructure[$shortPrintName, resultStructure], LIST[resultStructure] ] ] ];
caminoItem.object ← result; -- 3/87 caminoItem.object not used
ViewerTools.SetContents[caminoItem.nameViewer, name]; -- 3/87 nameViewer not used
ViewerOps.PaintViewer[caminoItem.outer, all]
};
};
Conversion Procs
ConvertToASRope: Menus.MenuProc ~ {
PROC [parent: Viewer, clientData: REF ANYNIL,
mouseButton: MouseButton ← red, shift, control: BOOLFALSE];
effects: pops up a new text viewer with contents = algebra system value (as a Rope) of primary selection
v: ViewerTools.Viewer ← NIL;
s: ExprViewerData ← NARROW[clientData];
primaryViewer: Viewer ← NIL;
primaryExpr: DisplayExpr ← NIL;
flavor: ATOMSELECT mouseButton FROM
red => $SMP,
yellow => $Reduce,
blue => $AS,
ENDCASE => ERROR;
IF ~ViewExprOps.Active[$primary] THEN {
MessageWindow.Append["Make a primary selection first.", TRUE];
MessageWindow.Blink[];
RETURN; -- no selection
};
[primaryViewer, primaryExpr] ← ViewExprOps.GetSelection[$primary];
pop up a new text viewer and convert to rope
v ← ViewerTools.MakeNewTextViewer[info: [name: Rope.Cat["Algebra System Rope for ", s.exprViewer.name], iconic: FALSE] ];
ViewerTools.SetContents[v, MathDisplayExpr.ASRopeFromDisplayExpr[primaryExpr, flavor]];
};
ConvertToExprRope: Menus.MenuProc ~ {
effects: Creates a new text viewer with contents = canonical output form of active seln.
v: ViewerTools.Viewer ← NIL;
s: ExprViewerData ← NARROW[clientData];
primaryViewer: Viewer ← NIL;
primaryExpr: DisplayExpr ← NIL;
ropeVal: ROPENIL;
make sure there is an active primary selection
IF ~ViewExprOps.Active[$primary] THEN {
MessageWindow.Append["Make a primary selection first.", TRUE];
MessageWindow.Blink[];
RETURN; -- no selection, so complain
};
get viewer & expression associated with primary selection
[primaryViewer, primaryExpr] ← ViewExprOps.GetSelection[$primary];
convert expression to rope
ropeVal ← MathExpr.RopeFromExpr[MathDisplayExpr.ExprFromDisplayExpr[primaryExpr]];
pop up a new text viewer containing rope
v ← ViewerTools.MakeNewTextViewer[info: [name: Rope.Cat["Expr Rope for ", s.exprViewer.name], iconic: FALSE ] ];
ViewerTools.SetContents[v, ropeVal];
};
ConvertFromExprRope: Menus.MenuProc ~ {
effects: Replaces primary selection with expression parsed from linear GetSelection ROPE.
local declarations
ropeVal: ROPE ← ViewerTools.GetSelectionContents[]; -- get rope from text selection
exprVal, primaryExpr: DisplayExpr ← NIL;
ok: BOOLTRUE;
primaryViewer: Viewer ← NIL;
make sure there is an active primary selection
IF ~ViewExprOps.Active[$primary] THEN {
MessageWindow.Append["Make a primary selection first.", TRUE];
MessageWindow.Blink[];
RETURN; -- no selection, so complain
};
get viewer & expression associated with primary selection
[primaryViewer, primaryExpr] ← ViewExprOps.GetSelection[$primary];
exprVal ← MathDisplayExpr.DisplayExprFromExpr[MathExpr.ExprFromRope[ropeVal ! MathExpr.parseError => {ok ← FALSE; CONTINUE}]];
IF ok THEN {
replace primary selection with exprVal
ReplaceInViewer[primaryViewer, primaryExpr, exprVal];
ViewExprOps.UnSelect[$primary];
ViewExprOps.FlushPaintQueue[]; -- update viewer contents
}
ELSE {
can't do it (parse error), so complain
MessageWindow.Append["Expression Format Error.", TRUE];
MessageWindow.Blink[];
};
};
ConvertToTioga: Menus.MenuProc ~ {
effects: Creates a new text viewer with contents = canonical output form of active seln.
v: ViewerTools.Viewer ← NIL;
s: ExprViewerData ← NARROW[clientData];
primaryViewer: Viewer ← NIL;
primaryExpr: DisplayExpr ← NIL;
ropeVal: ROPENIL;
make sure there is an active primary selection
IF ~ViewExprOps.Active[$primary] THEN {
MessageWindow.Append["Make a primary selection first.", TRUE];
MessageWindow.Blink[];
RETURN; -- no selection, so complain
};
get viewer & expression associated with primary selection
[primaryViewer, primaryExpr] ← ViewExprOps.GetSelection[$primary];
convert expression to rope
ropeVal ← MathExpr.RopeFromExpr[MathDisplayExpr.ExprFromDisplayExpr[primaryExpr]];
pop up a new text viewer containing rope
v ← ViewerTools.MakeNewTextViewer[info: [name: Rope.Cat["Rope for ", s.exprViewer.name]]];
ViewerTools.SetContents[v, ropeVal];
};
WriteHeader: PUBLIC PROC [exprRope: ROPE] RETURNS [ROPE] ~ {
Header has length 50.
header: ROPE = "CaminoRealExpressionRepresentationVersion1.1 "; -- January 6, 1987 11:28:10 am PST
RETURN[ Rope.Concat[header, exprRope] ]; -- attach header
};
StripHeader: PUBLIC PROC [exprRope: ROPE] RETURNS [ROPE] ~ {
headerLength: CARDINAL = 50;
IF Rope.Equal[Rope.Substr[exprRope,0,6], "Camino"] THEN
RETURN[ Rope.Substr[exprRope, headerLength, Rope.Length[exprRope] ] ]
ELSE RETURN[exprRope];
};
ConvertToTioga: Menus.MenuProc ~ {
metersPerPoint: REAL ← 254.0/720000.0;
mmPerPoint: REAL ← 254.0/720.0;
topSpace: REAL ← 8.0*mmPerPoint;
bottomSpace: REAL ← 4.0*mmPerPoint;
TeXToTioga: REAL ~ 20.0; -- default scaling factor from unit-sized TeX Fonts to Tioga
MeddleSelectionToRope: PROC [] RETURNS [ROPE] ~ {
primaryExpr: MathDisplayExpr.DisplayExpr ← NIL;
make sure there is an active primary selection
IF ~ViewExprOps.Active[$primary] THEN {
MessageWindow.Append["Make a primary selection first.", TRUE];
MessageWindow.Blink[];
RETURN[NIL]; -- no selection, so complain
};
get viewer & expression associated with primary selection
[----, primaryExpr] ← ViewExprOps.GetSelection[$primary];
convert expression to rope
RETURN[MathExpr.RopeFromExpr[MathDisplayExpr.ExprFromDisplayExpr[primaryExpr] ] ];
};
WriteArtwork: PUBLIC PROC [writer: TiogaAccess.Writer, pointSize: REAL] RETURNS [ok: BOOLTRUE] ~ {
tc: TiogaAccess.TiogaChar ← [
charSet: 0,
char: 'X,
looks: ALL[FALSE],
format: NIL,
comment: TRUE,
endOfNode: FALSE,
deltaLevel: 0,
propList: NIL
];
PutRope: PROC [rope: ROPE] ~ {
action: Rope.ActionType ~ {tc.char ← c; TiogaAccess.Put[writer, tc]};
[] ← Rope.Map[base: rope, action: action];
};
PutRopeProp: PROC [key: ATOM, val: ROPE] ~ {
tc.propList ← CONS[NEW[Atom.DottedPairNode ← [key: key, val: val]], tc.propList];
};
displayBox: MathBox.BOXNIL;
displayExpr: MathDisplayExpr.DisplayExpr ← NIL;
mathExpr: MathExpr.EXPRNIL;
postfixValue, leading, topLeading, bottomLeading: ROPENIL; -- for postfix properties
linearExpr: ROPE ← MeddleSelectionToRope[];
IF linearExpr=NIL THEN RETURN[FALSE];
convert linear form of expression to internal form
mathExpr ← MathExpr.ExprFromRope[linearExpr ! MathExpr.parseError => {mathExpr ← MathConstructors.MakePlaceHolder[]; CONTINUE}];
convert immutable expression to mutable display form
displayExpr ← MathDisplayExpr.DisplayExprFromExpr[mathExpr];
format expression and get box dimensions
displayBox ← displayExpr.Format[normal];
scale box dimensions from TeX unit sizes to some reasonable size
displayBox ← MathBox.Scale[displayBox, [pointSize, pointSize]];
compute appropriate postfix point values to place on current node
in order to set a maximum value, the following JaM code fragment does this
mumble pt the leading 2 .copy .gt 3 1 .roll .ifelse leading
leading ← Convert.RopeFromReal[displayBox.Height[]];
topLeading ← Convert.RopeFromReal[displayBox.Extents[].ascent + 12.0];
bottomLeading ← Convert.RopeFromReal[displayBox.Extents[].descent + 12.0];
postfixValue ← Rope.Cat[leading, " pt the leading 2 .copy .gt 3 1 .roll .ifelse leading "];
postfixValue ← Rope.Cat[postfixValue, topLeading, " pt the topLeading 2 .copy .gt 3 1 .roll .ifelse topLeading "];
postfixValue ← Rope.Cat[postfixValue, topLeading, " pt the topIndent 2 .copy .gt 3 1 .roll .ifelse topIndent "];
postfixValue ← Rope.Cat[postfixValue, bottomLeading, " pt the bottomLeading 2 .copy .gt 3 1 .roll .ifelse bottomLeading "];
tc.endOfNode ← TRUE; PutRope["X"]; tc.endOfNode ← FALSE;
PutLooksRope[" [Artwork node; type 'MeddleArtwork on' to command tool] ", 'n]; -- char looks
PutRopeProp[$Postfix, postfixValue]; -- should this be on the Node ??
PutRopeProp[$Artwork, "MeddleExpr"];
PutRopeProp[$MeddleExpr, WriteHeader[linearExpr] ];
PutRopeProp[$MeddlePtSize, pointSizeRope];
end of char props
TiogaAccess.Put[writer, tc]; -- puts everything at once
};
caminoItem: CaminoItem ← NARROW[clientData];
pointSizeRope: ROPE ← ViewerTools.GetContents[caminoItem.scratchPadViewer];
pointSize: REAL ← TeXToTioga;
selectionViewer: TiogaOps.Viewer ← TiogaOps.GetSelection[primary].viewer;
writer: TiogaAccess.Writer ← TiogaAccess.Create[];
locked: PROC [root: TextNode.Ref, tSel: TEditDocument.Selection] ~ {
TEditInputOps.Break[];
TiogaAccess.WriteSelection[writer]; -- replaces the primary selection
};
IF NOT Rope.Equal[pointSizeRope,""] THEN pointSize ← Convert.RealFromRope[pointSizeRope];
IF WriteArtwork[writer: writer, pointSize: pointSize] THEN {
TEditInputOps.CallWithLocks[locked];
ViewerOps.PaintViewer[viewer: selectionViewer, hint: client];
};
};
PlaceInTioga: PROC [caminoItem: CaminoItem, linearExpr: ROPE] ~ {
metersPerPoint: REAL ← 254.0/720000.0;
mmPerPoint: REAL ← 254.0/720.0;
topSpace: REAL ← 8.0*mmPerPoint;
bottomSpace: REAL ← 4.0*mmPerPoint;
TeXToTioga: REAL ~ 20.0; -- default scaling factor from unit-sized TeX Fonts to Tioga
WriteArtwork: PUBLIC PROC [writer: TiogaAccess.Writer, pointSize: REAL] RETURNS [ok: BOOLTRUE] ~ {
tc: TiogaAccess.TiogaChar ← [
charSet: 0,
char: 'X,
looks: ALL[FALSE],
format: NIL,
comment: TRUE,
endOfNode: FALSE,
deltaLevel: 0,
propList: NIL
];
PutRope: PROC [rope: ROPE] ~ {
action: Rope.ActionType ~ {tc.char ← c; TiogaAccess.Put[writer, tc]};
[] ← Rope.Map[base: rope, action: action];
};
PutRopeProp: PROC [key: ATOM, val: ROPE] ~ {
tc.propList ← CONS[NEW[Atom.DottedPairNode ← [key: key, val: val]], tc.propList];
};
displayBox: MathBox.BOXNIL;
displayExpr: MathDisplayExpr.DisplayExpr ← NIL;
mathExpr: MathExpr.EXPRNIL;
postfixValue, leading, topLeading, bottomLeading: ROPENIL; -- for postfix properties
IF linearExpr=NIL THEN RETURN[FALSE];
convert linear form of expression to internal form
mathExpr ← MathExpr.ExprFromRope[linearExpr ! MathExpr.parseError => {mathExpr ← MathConstructors.MakePlaceHolder[]; CONTINUE}];
convert immutable expression to mutable display form
displayExpr ← MathDisplayExpr.DisplayExprFromExpr[mathExpr];
format expression and get box dimensions
displayBox ← displayExpr.Format[normal];
scale box dimensions from TeX unit sizes to some reasonable size
displayBox ← MathBox.Scale[displayBox, [pointSize, pointSize]];
compute appropriate postfix point values to place on current node
in order to set a maximum value, the following JaM code fragment does this
mumble pt the leading 2 .copy .gt 3 1 .roll .ifelse leading
leading ← Convert.RopeFromReal[displayBox.Height[]];
topLeading ← Convert.RopeFromReal[displayBox.Extents[].ascent + 12.0];
bottomLeading ← Convert.RopeFromReal[displayBox.Extents[].descent + 12.0];
postfixValue ← Rope.Cat[leading, " pt the leading 2 .copy .gt 3 1 .roll .ifelse leading "];
postfixValue ← Rope.Cat[postfixValue, topLeading, " pt the topLeading 2 .copy .gt 3 1 .roll .ifelse topLeading "];
postfixValue ← Rope.Cat[postfixValue, topLeading, " pt the topIndent 2 .copy .gt 3 1 .roll .ifelse topIndent "];
postfixValue ← Rope.Cat[postfixValue, bottomLeading, " pt the bottomLeading 2 .copy .gt 3 1 .roll .ifelse bottomLeading "];
tc.endOfNode ← TRUE; PutRope["X"]; tc.endOfNode ← FALSE;
PutLooksRope[" [Artwork node; type 'MeddleArtwork on' to command tool] ", 'n]; -- char looks
PutRopeProp[$Postfix, postfixValue]; -- should this be on the Node ??
PutRopeProp[$Artwork, "MeddleExpr"];
PutRopeProp[$MeddleExpr, WriteHeader[linearExpr] ];
PutRopeProp[$MeddlePtSize, pointSizeRope];
end of char props
TiogaAccess.Put[writer, tc]; -- puts everything at once
};
pointSizeRope: ROPE ← ViewerTools.GetContents[caminoItem.scratchPadViewer];
pointSize: REAL ← TeXToTioga;
selectionViewer: TiogaOps.Viewer ← TiogaOps.GetSelection[primary].viewer;
writer: TiogaAccess.Writer ← TiogaAccess.Create[];
locked: PROC [root: TextNode.Ref, tSel: TEditDocument.Selection] ~ {
TEditInputOps.Break[];
TiogaAccess.WriteSelection[writer]; -- replaces the primary selection
};
IF NOT Rope.Equal[pointSizeRope,""] THEN pointSize ← Convert.RealFromRope[pointSizeRope];
IF WriteArtwork[writer: writer, pointSize: pointSize] THEN {
TEditInputOps.CallWithLocks[locked];
ViewerOps.PaintViewer[viewer: selectionViewer, hint: client];
};
};
ConvertFromTioga: Menus.MenuProc ~ {
effects: Replaces primary selection with expression parsed from linear GetSelection ROPE.
local declarations
ropeVal: ROPE ← ViewerTools.GetSelectionContents[]; -- get rope from text selection
caminoItem: CaminoItem ← NARROW[clientData];
location: TiogaOps.Location ← TiogaOps.GetSelection[primary].start;
selection: TextEdit.RefTextNode ← location.node;
exprRope: ROPENARROW[TextEdit.GetCharProp[selection, location.where, $MeddleExpr]];
exprPtSize: ROPENARROW[TextEdit.GetCharProp[selection, location.where, $MeddlePtSize]];
exprVal, primaryExpr: DisplayExpr ← NIL;
ok: BOOLTRUE;
primaryViewer: Viewer ← NIL;
make sure there is an active primary selection
IF ~ViewExprOps.Active[$primary] THEN {
MessageWindow.Append["Make a primary selection first.", TRUE];
MessageWindow.Blink[];
RETURN; -- no selection, so complain
};
get viewer & expression associated with primary selection
[primaryViewer, primaryExpr] ← ViewExprOps.GetSelection[$primary];
strip header if present, and convert to DisplayExpr
exprVal ← MathDisplayExpr.DisplayExprFromExpr[MathExpr.ExprFromRope[ StripHeader[exprRope] ! MathExpr.parseError => {ok ← FALSE; CONTINUE}] ];
IF ok THEN {
replace primary selection with exprVal, MeddlePtSize value into ScratchPad
ReplaceInViewer[primaryViewer, primaryExpr, exprVal];
ViewerTools.SetContents[caminoItem.scratchPadViewer, exprPtSize];
ViewExprOps.UnSelect[$primary];
ViewExprOps.FlushPaintQueue[]; -- update viewer contents
}
ELSE {
can't do it (parse error), so complain
MessageWindow.Append["Expression Format Error.", TRUE];
MessageWindow.Blink[];
};
};
SetPtSize: Menus.MenuProc ~ {
effects: Read value of $MeddlePtSize from ScratchPad, and set $MeddlePtSize property in an expression already in a Tioga Doc
TeXToTioga: REAL ~ 20.0; -- default scaling factor from unit-sized TeX Fonts to Tioga
WriteArtwork: PUBLIC PROC [writer: TiogaAccess.Writer, pointSize: REAL] RETURNS [ok: BOOLTRUE] ~ {
tc: TiogaAccess.TiogaChar ← [
charSet: 0,
char: 'X,
looks: ALL[FALSE],
format: NIL,
comment: TRUE,
endOfNode: FALSE,
deltaLevel: 0,
propList: NIL
];
PutRopeProp: PROC [key: ATOM, val: ROPE] ~ {
tc.propList ← CONS[NEW[Atom.DottedPairNode ← [key: key, val: val]], tc.propList];
};
TeXToTioga: REAL ~ 20.0; -- default scaling factor from unit-sized TeX Fonts to Tioga
pointSize: REAL ← TeXToTioga; -- point size to use when rendering MEDDLE expr
displayBox: MathBox.BOXNIL;
displayExpr: MathDisplayExpr.DisplayExpr ← NIL;
mathExpr: MathExpr.EXPRNIL;
postfixValue, leading, topLeading, bottomLeading: ROPENIL; -- for postfix properties
IF exprRope=NIL THEN RETURN[FALSE];
convert linear form of expression to internal form
mathExpr ← MathExpr.ExprFromRope[StripHeader[exprRope] ! MathExpr.parseError => {mathExpr ← MathConstructors.MakePlaceHolder[]; CONTINUE}];
convert immutable expression to mutable display form
displayExpr ← MathDisplayExpr.DisplayExprFromExpr[mathExpr];
format expression and get box dimensions
displayBox ← displayExpr.Format[normal];
scale box dimensions from TeX unit sizes to some reasonable size
displayBox ← MathBox.Scale[displayBox, [pointSize, pointSize]];
compute appropriate postfix point values to place on current node
in order to set a maximum value, the following JaM code fragment does this
mumble pt the leading 2 .copy .gt 3 1 .roll .ifelse leading
leading ← Convert.RopeFromReal[displayBox.Height[]];
topLeading ← Convert.RopeFromReal[displayBox.Extents[].ascent + 12.0];
bottomLeading ← Convert.RopeFromReal[displayBox.Extents[].descent + 12.0];
postfixValue ← Rope.Cat[leading, " pt the leading 2 .copy .gt 3 1 .roll .ifelse leading "];
postfixValue ← Rope.Cat[postfixValue, topLeading, " pt the topLeading 2 .copy .gt 3 1 .roll .ifelse topLeading "];
postfixValue ← Rope.Cat[postfixValue, topLeading, " pt the topIndent 2 .copy .gt 3 1 .roll .ifelse topIndent "];
postfixValue ← Rope.Cat[postfixValue, bottomLeading, " pt the bottomLeading 2 .copy .gt 3 1 .roll .ifelse bottomLeading "];
tc.endOfNode ← TRUE; PutRope["X"]; tc.endOfNode ← FALSE;
PutLooksRope[" [Artwork node; type 'MeddleArtwork on' to command tool] ", 'n]; -- char looks
PutRopeProp[$Postfix, postfixValue]; -- should this be on the Node ??
PutRopeProp[$Artwork, "MeddleExpr"];
PutRopeProp[$MeddleExpr, exprRope];
PutRopeProp[$MeddlePtSize, newPtSizeRope];
end of char props
TiogaAccess.Put[writer, tc]; -- puts everything at once
};
caminoItem: CaminoItem ← NARROW[clientData];
newPtSizeRope: ROPE ← ViewerTools.GetContents[caminoItem.scratchPadViewer]; -- get rope from ScratchPad (should be convertible to a REAL)
newPtSize: REAL ← Convert.RealFromRope[newPtSizeRope];
selectionViewer: TiogaOps.Viewer ← TiogaOps.GetSelection[primary].viewer;
location: TiogaOps.Location ← TiogaOps.GetSelection[primary].start;
selection: TextEdit.RefTextNode ← location.node;
exprRope: ROPENARROW[TextEdit.GetCharProp[selection, location.where, $MeddleExpr]];
writer: TiogaAccess.Writer ← TiogaAccess.Create[];
locked: PROC [root: TextNode.Ref, tSel: TEditDocument.Selection] ~ {
TEditInputOps.Break[];
TiogaAccess.WriteSelection[writer]; -- replaces the primary selection
};
IF WriteArtwork[writer: writer, pointSize: newPtSize] THEN {
TEditInputOps.CallWithLocks[locked];
ViewerOps.PaintViewer[viewer: selectionViewer, hint: client];
};
};
Debugging
Break: SIGNAL = CODE;
EnterDebugger: Menus.MenuProc ~ {
effects: SIGNALS Break to enter the symbolic debugger.
s: ExprViewerData ← NARROW[clientData];
expr: DisplayExpr ← s.displayExpr;
SIGNAL Break;
};
Start Code
RegisterExprViewerClass[];
Register a command with the UserExec that will create an instance of this tool.
Commander.Register[key: "CaminoReal", proc: MakeCaminoItem,
doc: "Create a new CaminoReal item" ];
[ ] ← MakeCaminoItem[NIL]; -- and create an instance
END.