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; 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; fontToViewerSizeRatio: REAL = 75.0; -- magnify from TeX font units to Viewer pixels 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 kbBuffer: Parser.KbBuffer; setSwap: BOOL _ FALSE; ignoreNextRightBracket: BOOL _ FALSE; MakeCaminoItem: Commander.CommandProc = BEGIN [] _ CreateCaminoItem["CaminoRealItem"]; END; CreateCaminoItem: PUBLIC PROC [name: ROPE, object: AlgebraClasses.Object _ NIL] RETURNS [CaminoItem] = BEGIN expr: EXPR _ IF 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.PaintViewer[my.outer, all];-- reflect above change 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, 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, 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, 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] ]; caminoItem.height _ caminoItem.height + entryHeight + entryVSpace; -- interline spacing END; PromptScratch: Buttons.ButtonProc = BEGIN 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: EXPR _ NIL] = 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 caminoItem: CaminoItem _ NARROW[clientData]; -- get our data caminoItem.name _ ViewerTools.GetContents[caminoItem.scratchPadViewer]; -- get name caminoItem.outer.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]; }; CreateExprViewer: PROC[parentItem: CaminoItem, x, y, w, h: INTEGER, expr: EXPR _ NIL] RETURNS[Viewer] ~ { 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: BOX _ NIL; -- box for displayExpr IF expression = NIL THEN expression _ MathConstructors.MakePlaceHolder[]; displayExpr _ MathDisplayExpr.DisplayExprFromExpr[expression]; displayBox _ displayExpr.Format[normal]; v _ ViewerOps.CreateViewer[ flavor: $expr, info: [ parent: parentItem.outer, wx: x, wy: y, ww: w, wh:h, scrollable: TRUE, hscrollable: TRUE] ]; s _ NARROW[v.data]; s.parentItem _ parentItem; s.displayExpr _ displayExpr; s.lastDisplayExpr _ displayExpr; -- for UNDO s.displayBox _ displayBox; RETURN[v]; }; InitializeExprViewer: ViewerClasses.InitProc ~ { self.data _ NEW[ExprViewerDataRec _ [ exprViewer: self, offsetX: 0.0, offsetY: 0.0, scale: 1.0, displayExpr: NIL, displayBox: NIL, physicalBox: NIL]]; }; VerticalScroll: ViewerClasses.ScrollProc ~ { s: ExprViewerData _ NARROW[self.data]; -- get viewer state info 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 ~ { s: ExprViewerData _ NARROW[self.data]; -- get viewer state info 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 ~ { s: ExprViewerData _ NARROW[self.data]; ViewExprOps.UnSelectViewer[self]; ViewExprOps.PaintDequeue[self]; s.exprViewer _ NIL; -- break up circular ref for GC }; NotifyExprViewer: ViewerClasses.NotifyProc ~ { [] _ 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 => { 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 => { 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 ViewExprOps.FlushPaintQueue[]; }; SelectionColor: PROC[flavor: ATOM] RETURNS[Imager.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]; 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 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)]]; FOR l: LIST OF ATOM _ LIST[$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; MathDisplayExpr.Paint[s.displayExpr, context, s.physicalBox, highlight]; }; RepaintViewer: PUBLIC PROC[viewer: Viewer] ~ { ViewExprOps.PaintEnqueue[viewer]; ViewExprOps.FlushPaintQueue[]; }; Home: Menus.MenuProc ~ { 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 ~ { 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 ~ { s: ExprViewerData _ NARROW[clientData]; UndoViewer[s.exprViewer]; }; UndoViewer: PROC[viewer: Viewer] ~ { state: ExprViewerData _ NARROW[viewer.data]; -- get current state ViewExprOps.UnSelectViewer[viewer]; SetViewerDisplayExpr[viewer, state.lastDisplayExpr]; ViewExprOps.Select[$primary, viewer, state.displayExpr]; ViewerOps.PaintViewer[viewer, client]; }; RegisterExprViewerClass: PROC ~ { 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 ]] ]; }; CopySecondaryToPrimary: PROC[] ~ { 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]; ViewExprOps.UnSelect[$primary]; ViewExprOps.UnSelect[$copy]; }; SwapSecondaryAndPrimary: PROC[] ~ { 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 { 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 { ReplaceInViewer[primaryViewer, primaryExpr, moveReplacement]; ReplaceInViewer[moveViewer, moveExpr, primaryReplacement]; ViewExprOps.UnSelect[$primary]; ViewExprOps.UnSelect[$move]; }; }; MoveSecondaryToPrimary: PROC[] ~ { 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 { 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 { ReplaceInViewer[primaryViewer, primaryExpr, moveReplacement]; ViewExprOps.UnSelect[$primary]; DeleteSelection[$move, FALSE]; }; }; CheckSelection: PROC [flavor: ATOM, thisViewer: Viewer _ NIL] RETURNS [ok: BOOL _ TRUE, 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 ~ { s: ExprViewerData _ NARROW[clientData]; SelectEntireViewer[s.exprViewer, $primary]; }; SelectEntireCopy: Menus.MenuProc ~ { s: ExprViewerData _ NARROW[clientData]; SelectEntireViewer[s.exprViewer, $copy]; }; SelectEntireViewer: PROC[viewer: Viewer, flavor: ATOM] ~ { state: ExprViewerData _ NARROW[viewer.data]; -- get current state ViewExprOps.UnSelectViewer[viewer]; ViewExprOps.Select[flavor, viewer, state.displayExpr]; [] _ InputFocus.SetInputFocus[viewer]; ViewerOps.PaintViewer[viewer, client]; }; ReplaceInViewer: PROC[viewer: Viewer, old, new: DisplayExpr] ~ { state: ExprViewerData _ NARROW[viewer.data]; replacement: DisplayExpr _ MathDisplayExpr.Replace[state.displayExpr, old, new]; SetViewerDisplayExpr[viewer, replacement]; }; SetViewerDisplayExpr: PROC[viewer: Viewer, replacement: DisplayExpr] ~ { 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: BOOL _ 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] ~ { 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]; }; GetPopUpMenuMethod: PROC [selection: INT, names: LIST OF ROPE, menuValueList: LIST OF Method] RETURNS [value: Method _ NIL, name: ROPE _ NIL] ~ { 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: ATOM _ NIL] ~ { 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]; }; EnterObject: Menus.MenuProc ~ { replacement: DisplayExpr _ NIL; opNames: LIST OF ROPE _ LIST["variable", "lowGreekVar", "uppGreekVar", "specialCharacter", "bool", "integer", "rational", "real", "complex", "set", "sequence", "vector", "matrix", "block", "parseRope"]; selection: INT _ 0; ok: BOOL _ TRUE; primaryViewer: Viewer _ NIL; primaryExpr: DisplayExpr _ NIL; textSelection: ROPE _ NIL; 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] ~ { RETURN[MathExpr.MakeAtomicExpr[$hat, XRope.FromChar['^, XRope.roman]]]; }; s: ExprViewerData _ NARROW[clientData]; [ok, primaryViewer, primaryExpr] _ CheckSelection[$primary, s.exprViewer]; IF ~ok THEN RETURN; selection _ PopUpSelection.Request[header: "Choose Object", choice: opNames]; { ENABLE MathConstructors.badFormat, Convert.Error => { MessageWindow.Append["Input format error.", TRUE]; MessageWindow.Blink[]; GOTO abort; }; 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 => { greekName: ROPE _ NIL; greekChoices: LIST OF ROPE _ LIST["alpha", "beta", "gamma", "delta", "epsilon", "zeta", "eta", "theta", "iota", "kappa", "lambda", "mu", "nu", "xi", "pi", "rho", "sigma", "tau", "upsilon", "phi", "chi", "psi", "omega"]; 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 selection _ selection - 1; IF selection = 0 THEN {greekName _ l.first; EXIT}; ENDLOOP; replacement _ MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakeGreekVar[greekName]]; }; uppGreekVar => { greekName: ROPE _ NIL; greekChoices: LIST OF ROPE _ LIST["Gamma", "Delta", "Theta", "Lambda", "Xi", "Pi", "Sigma", "Upsilon", "Phi", "Psi", "Omega"]; 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 selection _ selection - 1; IF selection = 0 THEN {greekName _ l.first; EXIT}; ENDLOOP; replacement _ MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakeGreekVar[greekName]]; }; specialCharacter => { specialCharName: ROPE _ NIL; specialCharChoices: LIST OF ROPE _ LIST["infinity", "rightArrow", "bar", "perp", "hat"]; infinity: INT = 1; rightArrow: INT = 2; bar: INT = 3; perp: INT = 4; hat: INT = 5; 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 => { oneToTen: LIST OF ROPE _ LIST["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]; dimension: INT _ 0; elements: LIST OF EXPR _ NIL; row: INT _ 0; -- =1 => row vector, =2 => col vector, ELSE => invalid rowVec: BOOL _ FALSE; -- TRUE iff vector is a row vector ok: BOOL _ TRUE; 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 => { oneToTen: LIST OF ROPE _ LIST["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]; nRows, nCols: INT _ 0; rows: LIST OF LIST OF EXPR _ NIL; ok: BOOL _ TRUE; 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 EXPR _ NIL; -- 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; IF selection#parseRope THEN { ViewExprOps.UnSelect[$primary]; -- unselect currently active selection ReplaceInViewer[primaryViewer, primaryExpr, replacement] }; ViewerOps.PaintViewer[s.exprViewer, client]; }; EXITS abort => NULL; }; ReplaceWithOperator: Menus.MenuProc ~ { ReplaceOrWrap[clientData: clientData, replace: TRUE]; }; WrapWithOperator: Menus.MenuProc ~ { ReplaceOrWrap[clientData: clientData, replace: FALSE]; }; GetOpClassName: PROC [opFamilyName: ATOM] RETURNS [opClassName: ATOM _ NIL] ~ { 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] ~ { selection: INT _ 0; opFamiliesNames: LIST OF ATOM _ MathDB.OpFamiliesNames[]; opClassName: ATOM; opFamilyName: ATOM; ok: BOOL _ TRUE; 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] ~ { nameExpr: EXPR _ MathConstructors.MakeVariable[Convert.RopeFromAtom[from: name, quote: FALSE] ]; argExpr: EXPR _ IF 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: BOOL _ FALSE] RETURNS[replacement, hotArg: DisplayExpr _ NIL]~ { exprClass: CompoundClass; argExprs: LIST OF MathExpr.TaggedMathExpr _ NIL; hotTag: ATOM; -- tag of "hot" argument ok: BOOL _ TRUE; 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}; ]; 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]] }; 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: BOOL _ FALSE] ~ { replacement, hotArg: DisplayExpr; [replacement, hotArg] _ MakeTemplate[class, blink]; ReplaceInViewer[viewer, expr, replacement]; ViewExprOps.UnSelect[$primary]; IF hotArg # NIL THEN ViewExprOps.Select[$primary, viewer, hotArg] ELSE ViewExprOps.Select[$primary, viewer, replacement]; RepaintViewer[viewer]; }; WrapTemplate: PROC [class: ATOM, expr: DisplayExpr, blink: BOOL _ FALSE] RETURNS[replacement, selectableSibling, wrapArg: DisplayExpr] ~ { exprClass: CompoundClass; -- class data associated with class argExprs: LIST OF MathExpr.TaggedMathExpr _ NIL; hotTag: ATOM; -- tag of "hot" argument ok: BOOL _ TRUE; replacement _ selectableSibling _ wrapArg _ NIL; 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 }; ]; IF ok THEN { FOR l: LIST OF Argument _ exprClass.arguments, l.rest UNTIL l = NIL DO hot: BOOL _ FALSE; 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]]; }; 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: BOOL _ FALSE] ~ { replacement, selectableSibling, wrapArg: DisplayExpr; [replacement, selectableSibling, wrapArg] _ WrapTemplate[class, expr, blink]; ReplaceInViewer[viewer, expr, replacement]; ViewExprOps.UnSelect[$primary]; IF selectableSibling # NIL THEN ViewExprOps.Select[$primary, viewer, selectableSibling] ELSE ViewExprOps.Select[$primary, viewer, wrapArg]; RepaintViewer[viewer]; }; PlaceHolder: PROC [] RETURNS [DisplayExpr] ~ { RETURN[MathDisplayExpr.DisplayExprFromExpr[MathConstructors.MakePlaceHolder[] ] ]; }; ParseActionFromChar: PROC[c: CHAR] ~ { action: Parser.ParseAction; 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; }; [kbBuffer, action] _ Parser.ParseKBChar[c, kbBuffer, ViewExprOps.Active[$primary], ViewExprOps.Active[$keyboard] ]; WITH action SELECT FROM r: REF Parser.ReplaceAction => { selectedViewer: Viewer _ NIL; selectedExpr, replacement: DisplayExpr _ NIL; ok: BOOL _ TRUE; [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 => { selectedViewer: Viewer _ NIL; selectedExpr: DisplayExpr _ NIL; ok: BOOL _ TRUE; [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: BOOL _ TRUE; [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 => { selectedViewer: Viewer _ NIL; selectedExpr, replacement: DisplayExpr _ NIL; ok: BOOL _ TRUE; [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[]; }; 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 => { ViewExprOps.Select[flavor, selectedViewer, MathDisplayExpr.SelectableParent[selectedExpr ! MathDisplayExpr.noSelection => {CONTINUE}]]; }; $PrimaryChildSelect => { ViewExprOps.Select[$primary, selectedViewer, MathDisplayExpr.SelectableChild[selectedExpr ! MathDisplayExpr.noSelection => {CONTINUE}]]; }; $PrimarySiblingSelect => { sibling: DisplayExpr; state: ExprViewerData; ok: BOOL _ TRUE; 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 => { 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] ~ { action: Parser.ParseAction; newOuter _ outerDisplayExpr; newPrimary _ primarySelection; newKeyboard _ keyboardSelection; [kbBuffer, action] _ Parser.ParseKBChar[c, kbBuffer, primarySelection#NIL, keyboardSelection#NIL ]; WITH action SELECT FROM r: REF Parser.ReplaceAction => { 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: BOOL _ TRUE; 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]; 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; }; 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; }; newOuter _ MathDisplayExpr.Replace[outerDisplayExpr, selectedExpr, replacement]; 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 => { 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 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 => { 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 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] ~ { 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 => { parent: DisplayExpr _ selection; parent _ MathDisplayExpr.SelectableParent[selection ! MathDisplayExpr.noSelection => {CONTINUE}]; RETURN[outerDisplayExpr, parent, NIL]; -- making a Primary => KB _ NIL }; $PrimaryChildSelect => { child: DisplayExpr _ selection; child _ MathDisplayExpr.SelectableChild[selection ! MathDisplayExpr.noSelection => {CONTINUE}]; RETURN[outerDisplayExpr, child, NIL]; }; $PrimarySiblingSelect => { sibling: DisplayExpr _ selection; sibling _ MathDisplayExpr.SelectableSibling[selection ! MathDisplayExpr.noSelection => {CONTINUE}]; RETURN[outerDisplayExpr, sibling, NIL]; }; 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 ] ~ { 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]; }; SetWorkingDomain: Buttons.ButtonProc = { caminoItem: CaminoItem _ NARROW[clientData]; -- get our data opNames: LIST OF ROPE _ LIST["Expressions", "Variables", "Bools", "Integers", "Rationals", "Reals", "Complexes", "SingleSet", "FamilyOfSets", "Sequences", "Vectors", "Matrices", "Polynomials"]; domain: Object; selection: INT _ 0; oneToTen: LIST OF ROPE _ LIST["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]; 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; 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; caminoItem.workingDomain _ domain; Labels.Set[caminoItem.workingDomainViewer, domain.name ]; }; ObjectFromSelection: PROC[flavor: ATOM, thisViewer: Viewer _ NIL] RETURNS [ok: BOOL _ TRUE, 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: BOOL _ TRUE; 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.STREAM _ FS.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.STREAM _ FS.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 ~ { ok: BOOL; primaryViewer: Viewer _ NIL; primaryExpr: DisplayExpr _ NIL; flavor: ATOM _ SELECT 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] ]; }; EvalTiogaInPlace: Menus.MenuProc ~ { caminoItem: CaminoItem _ NARROW[clientData]; ok: BOOL _ TRUE; evalExpr: EXPR; evalObject, evalObjectStructure: AC.Object; toExprMethod: AC.Method; linearExpr: ROPE; exprVal: EXPR _ NIL; location: TiogaOps.Location _ TiogaOps.GetSelection[primary].start; selection: TextEdit.RefTextNode _ location.node; exprRope: ROPE _ NARROW[TextEdit.GetCharProp[selection, location.where, $MeddleExpr]]; exprPtSize: ROPE _ NARROW[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 }; 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: BOOL _ TRUE, sourceStructureForMethod: Object _ NIL] ~ { opNames: LIST OF ROPE; operators: LIST OF Method; operator: Method; choiceRope: ROPE; refOps: LIST OF REF _ NIL; 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 methodStructure=NIL THEN { [ok, primaryViewer, primaryExpr, firstArg] _ ObjectFromSelection[$primary]; IF NOT ok THEN RETURN; methodStructure _ firstArg.class; }; [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]; 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]; } 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; }; 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: EXPR _ AC.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: BOOL _ TRUE] ~ { 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: EXPR _ AC.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] ] ] ]; ViewerOps.PaintViewer[caminoItem.outer, all] }; }; ConvertToASRope: Menus.MenuProc ~ { v: ViewerTools.Viewer _ NIL; s: ExprViewerData _ NARROW[clientData]; primaryViewer: Viewer _ NIL; primaryExpr: DisplayExpr _ NIL; flavor: ATOM _ SELECT 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]; 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 ~ { v: ViewerTools.Viewer _ NIL; s: ExprViewerData _ NARROW[clientData]; primaryViewer: Viewer _ NIL; primaryExpr: DisplayExpr _ NIL; ropeVal: ROPE _ NIL; IF ~ViewExprOps.Active[$primary] THEN { MessageWindow.Append["Make a primary selection first.", TRUE]; MessageWindow.Blink[]; RETURN; -- no selection, so complain }; [primaryViewer, primaryExpr] _ ViewExprOps.GetSelection[$primary]; ropeVal _ MathExpr.RopeFromExpr[MathDisplayExpr.ExprFromDisplayExpr[primaryExpr]]; v _ ViewerTools.MakeNewTextViewer[info: [name: Rope.Cat["Expr Rope for ", s.exprViewer.name], iconic: FALSE ] ]; ViewerTools.SetContents[v, ropeVal]; }; ConvertFromExprRope: Menus.MenuProc ~ { ropeVal: ROPE _ ViewerTools.GetSelectionContents[]; -- get rope from text selection exprVal, primaryExpr: DisplayExpr _ NIL; ok: BOOL _ TRUE; primaryViewer: Viewer _ NIL; IF ~ViewExprOps.Active[$primary] THEN { MessageWindow.Append["Make a primary selection first.", TRUE]; MessageWindow.Blink[]; RETURN; -- no selection, so complain }; [primaryViewer, primaryExpr] _ ViewExprOps.GetSelection[$primary]; exprVal _ MathDisplayExpr.DisplayExprFromExpr[MathExpr.ExprFromRope[ropeVal ! MathExpr.parseError => {ok _ FALSE; CONTINUE}]]; IF ok THEN { ReplaceInViewer[primaryViewer, primaryExpr, exprVal]; ViewExprOps.UnSelect[$primary]; ViewExprOps.FlushPaintQueue[]; -- update viewer contents } ELSE { MessageWindow.Append["Expression Format Error.", TRUE]; MessageWindow.Blink[]; }; }; WriteHeader: PUBLIC PROC [exprRope: ROPE] RETURNS [ROPE] ~ { 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; IF ~ViewExprOps.Active[$primary] THEN { MessageWindow.Append["Make a primary selection first.", TRUE]; MessageWindow.Blink[]; RETURN[NIL]; -- no selection, so complain }; [----, primaryExpr] _ ViewExprOps.GetSelection[$primary]; RETURN[MathExpr.RopeFromExpr[MathDisplayExpr.ExprFromDisplayExpr[primaryExpr] ] ]; }; WriteArtwork: PUBLIC PROC [writer: TiogaAccess.Writer, pointSize: REAL] RETURNS [ok: BOOL _ TRUE] ~ { 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]; }; displayBox: MathBox.BOX _ NIL; displayExpr: MathDisplayExpr.DisplayExpr _ NIL; mathExpr: MathExpr.EXPR _ NIL; postfixValue, leading, topLeading, bottomLeading: ROPE _ NIL; -- for postfix properties linearExpr: ROPE _ MeddleSelectionToRope[]; IF linearExpr=NIL THEN RETURN[FALSE]; mathExpr _ MathExpr.ExprFromRope[linearExpr ! MathExpr.parseError => {mathExpr _ MathConstructors.MakePlaceHolder[]; CONTINUE}]; displayExpr _ MathDisplayExpr.DisplayExprFromExpr[mathExpr]; displayBox _ displayExpr.Format[normal]; displayBox _ MathBox.Scale[displayBox, [pointSize, pointSize]]; 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 "]; PutRopeProp[$Postfix, postfixValue]; -- should this be on the Node ?? PutRopeProp[$Artwork, "MeddleExpr"]; PutRopeProp[$MeddleExpr, WriteHeader[linearExpr] ]; PutRopeProp[$MeddlePtSize, pointSizeRope]; 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] ~ { 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: BOOL _ TRUE] ~ { 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]; }; displayBox: MathBox.BOX _ NIL; displayExpr: MathDisplayExpr.DisplayExpr _ NIL; mathExpr: MathExpr.EXPR _ NIL; postfixValue, leading, topLeading, bottomLeading: ROPE _ NIL; -- for postfix properties IF linearExpr=NIL THEN RETURN[FALSE]; mathExpr _ MathExpr.ExprFromRope[linearExpr ! MathExpr.parseError => {mathExpr _ MathConstructors.MakePlaceHolder[]; CONTINUE}]; displayExpr _ MathDisplayExpr.DisplayExprFromExpr[mathExpr]; displayBox _ displayExpr.Format[normal]; displayBox _ MathBox.Scale[displayBox, [pointSize, pointSize]]; 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 "]; PutRopeProp[$Postfix, postfixValue]; -- should this be on the Node ?? PutRopeProp[$Artwork, "MeddleExpr"]; PutRopeProp[$MeddleExpr, WriteHeader[linearExpr] ]; PutRopeProp[$MeddlePtSize, pointSizeRope]; 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] ~ { 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 ~ { caminoItem: CaminoItem _ NARROW[clientData]; location: TiogaOps.Location _ TiogaOps.GetSelection[primary].start; selection: TextEdit.RefTextNode _ location.node; exprRope: ROPE _ NARROW[TextEdit.GetCharProp[selection, location.where, $MeddleExpr]]; exprPtSize: ROPE _ NARROW[TextEdit.GetCharProp[selection, location.where, $MeddlePtSize]]; exprVal, primaryExpr: DisplayExpr _ NIL; ok: BOOL _ TRUE; primaryViewer: Viewer _ NIL; IF ~ViewExprOps.Active[$primary] THEN { MessageWindow.Append["Make a primary selection first.", TRUE]; MessageWindow.Blink[]; RETURN; -- no selection, so complain }; [primaryViewer, primaryExpr] _ ViewExprOps.GetSelection[$primary]; exprVal _ MathDisplayExpr.DisplayExprFromExpr[MathExpr.ExprFromRope[ StripHeader[exprRope] ! MathExpr.parseError => {ok _ FALSE; CONTINUE}] ]; IF ok THEN { ReplaceInViewer[primaryViewer, primaryExpr, exprVal]; ViewerTools.SetContents[caminoItem.scratchPadViewer, exprPtSize]; ViewExprOps.UnSelect[$primary]; ViewExprOps.FlushPaintQueue[]; -- update viewer contents } ELSE { MessageWindow.Append["Expression Format Error.", TRUE]; MessageWindow.Blink[]; }; }; SetPtSize: Menus.MenuProc ~ { TeXToTioga: REAL ~ 20.0; -- default scaling factor from unit-sized TeX Fonts to Tioga WriteArtwork: PUBLIC PROC [writer: TiogaAccess.Writer, pointSize: REAL] RETURNS [ok: BOOL _ TRUE] ~ { 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]; }; displayBox: MathBox.BOX _ NIL; displayExpr: MathDisplayExpr.DisplayExpr _ NIL; mathExpr: MathExpr.EXPR _ NIL; postfixValue, leading, topLeading, bottomLeading: ROPE _ NIL; -- for postfix properties IF exprRope=NIL THEN RETURN[FALSE]; mathExpr _ MathExpr.ExprFromRope[StripHeader[exprRope] ! MathExpr.parseError => {mathExpr _ MathConstructors.MakePlaceHolder[]; CONTINUE}]; displayExpr _ MathDisplayExpr.DisplayExprFromExpr[mathExpr]; displayBox _ displayExpr.Format[normal]; displayBox _ MathBox.Scale[displayBox, [pointSize, pointSize]]; 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 "]; PutRopeProp[$Postfix, postfixValue]; -- should this be on the Node ?? PutRopeProp[$Artwork, "MeddleExpr"]; PutRopeProp[$MeddleExpr, exprRope]; PutRopeProp[$MeddlePtSize, newPtSizeRope]; 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: ROPE _ NARROW[TextEdit.GetCharProp[selection, location.where, $MeddleExpr]]; writer: TiogaAccess.Writer _ TiogaAccess.Create[]; locked: PROC [root: TextNode.Ref, tSel: TEditDocument.Selection] ~ { TiogaAccess.WriteSelection[writer]; -- replaces the primary selection }; IF WriteArtwork[writer: writer, pointSize: newPtSize] THEN { TEditInputOps.CallWithLocks[locked]; ViewerOps.PaintViewer[viewer: selectionViewer, hint: client]; }; }; Break: SIGNAL = CODE; EnterDebugger: Menus.MenuProc ~ { s: ExprViewerData _ NARROW[clientData]; expr: DisplayExpr _ s.displayExpr; SIGNAL Break; }; RegisterExprViewerClass[]; Commander.Register[key: "CaminoReal", proc: MakeCaminoItem, doc: "Create a new CaminoReal item" ]; END. E°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 Type Abbreviations From Imported Interfaces Constants Type Definitions Global Data (global only to this module) *** a+-b hack 7/16/87 *** CaminoReal Viewer management ViewerOps.SetOpenHeight[my.outer, my.height]; -- hint our desired height (SampleTool) ViewerOps.PaintViewer[my.exprViewer, client];-- get expression viewer sized default the width so that it will be computed for us -- default the width so that it will be computed for us -- default the width so that it will be computed for us -- 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] ]; force the selection into the user input field attach the name to the Camino item and its container, also to object if any IF caminoItem.object # NIL THEN caminoItem.object.name _ caminoItem.name; newItem.workingDomain _ domain; IF domain#NIL THEN Labels.Set[newItem.workingDomainViewer, domain.class.shortPrintName[domain] ]; ExprViewer management 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". If expr to display is defaulted, use empty placeholder instantiate new viewer set its state paint new viewer ViewerOps.PaintViewer[v, all]; return the newly spawned viewer effects: Initializes an expression viewer instance. effects: Performs verical scrolling of an expression viewer. compute current top & bottom percentage visible metrics effects: Performs horizontal scrolling of an expression viewer. compute current left & right percentage visible metrics effects: Peforms orderly termination of an expression viewer. if self contains any selections, unselect them remove self from paint queue 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 can't make a move selection w/o an existing primary selection can't make a copy selection w/o an existing primary selection flush any pending paint requests effects: Returns the color associated with flavor. If no such association exists, uses "$Invert" color. effects: Repaints contents of an expression viewer. local declarations modify scale factor by user-specified growth factor cons up list of selections to highlight spray the bits onto screen via imager effects: Repaints viewer after zeroing all offsets from scrolling. 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 effects: "Undoes" last action on viewer by restoring previously saved state. modifies: viewer effects: Restores viewer state (expression & box info) to previous state. cancel any current selections in viewer since UNDO may invalidate them replace current expr by last saved expr, set primary selection to whole thing now paint the viewer so UNDO is seen effects: Registers a new viewer class for expression viewers. Meddle (CaminoReal) Selections management effects: If both primary and secondary selections are active, replaces primary selection by secondary selection. local declarations select ops below will repaint viewers to reflect replacement effects: If both primary and secondary selections are active, swap primary and secondary selections. local declarations same viewer, so use ReplaceN to make two simultaneous replacements different viewers, so do one replacement at a time select ops below will repaint viewers to reflect replacement effects: If both primary and move selections are active, replaces primary selection by move selection and deletes secondary selection. local declarations same viewer, so use ReplaceN to make two simultaneous replacements different viewers, so do one replacement at a time select ops below will repaint viewers to reflect replacement effects: Make primary selection entire current Display Expression. effects: Make primary selection entire current Display Expression. modifies: viewer effects: Make flavor selection entire current Display Expression. cancel any current selections in viewer since UNDO may invalidate them Select entire current display expr grab the input focus so keyboard events get parsed now paint the viewer so new selection is seen 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. 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. effects: Deletes selection of type flavor, if active. Replaces selection with an expression "placeholder". This placeholder remians selected iff reselect is TRUE. effects: Rename oldFlavor selection, if active, to newFlavor. PopUpMenu utilities Like GetPopUpMenuAtom except for Methods PopUpMenu-driven Expression Editing effects: Replaces active selection with an atomic expression. Returns without action if any errors (e.g. parsing) occur. local declarations constants effects: Constructs and returns an expression for +infinity. do pop-up menu get text viewer selection, if any (not all opNames use this) local declarations display a second pop-up menu to choose greek letter from match selection (INT) with class name (ROPE -> ATOM) local declarations display a second pop-up menu to choose greek letter from match selection (INT) with class name (ROPE -> ATOM) local declarations display a second pop-up menu to choose specialCharacter from 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. 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. replace active selection repaint viewer to reflect replacement effects: Wraps around primarySelection a template for an expression type 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. 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). 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 lookup classname in database; make unaryFunction if not found create expressions for each argument to make LIST OF TaggedMathExpr get hook onto hot arg 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 replace expr in viewer with replacement if possible, select hotArg as primary selection, else select whole thing repaint viewer to reflect replacement 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. lookup classname in database; wrap unaryFunction if not found create expressions for each argument to make LIST OF TaggedMathExpr find selectable sibling, if any. 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. replace expr in viewer with replacement if possible, select sibling as primary selection, else select what got wrapped Keyboard-driven Expression Editing 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 character parsing only meaningful if either a primary or KB selection active parse character, determine action perform parse action local declarations local declarations local declarations u: REF Parser.UndoAction => UndoViewer[viewer]; extend selection to its parent change active primary or keyboard selection to its child as a primary selection Change active primary or keyboard selection to a sibling as primary selection. Alters selectedViewer.displayExpr if function extension hack happens. convert active keyboard selection to primary selection 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 Initializations parse character, determine action perform parse action local declarations *** Begin parenthesis hack 7/15/87 *** End parenthesis hack 7/15/87 *** Begin a+-b hack 7/16/87 *** End a+-b hack if possible, select hotArg as primary selection, else select whole thing local declarations if possible, select sibling as primary selection, else select what got wrapped local declarations if possible, select sibling as primary selection, else select what got wrapped Assumes outerDisplayExpr contains primarySelection and keyboardSelection extend selection to its parent change active primary or keyboard selection to its child as a primary selection Change active primary or keyboard selection to a sibling as primary selection. Alters outerDisplayExpr if function extension hack happens. $PrimaryDelete => { -- should be doable in here $EvalPrimaryInPlace => { -- -- should be doable in here Replaces primary selection with the result of parsing a Rope Domain (Structure) management opNames: LIST OF ROPE _ LIST["Bools", "Colors", "FormulaOperators", "Integers", "Rationals", "Reals", "Complexes", "Matrices", "Polynomials", "Formulas", "RealAlgebraicNumbers", "ExtensionField", "Points", "Sequences", "SamplePoints", "CoveringSets", "Cells", "Cads"]; constants Do pop-up menu Associate this domain with this Camino item Evaluation of Meddle and Tioga selections caminoItem: CaminoItem _ NARROW[clientData]; s: ExprViewerData _ NARROW[caminoItem.exprViewer.data]; v: ViewerTools.Viewer; 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]; effects: Eval Tioga selection in place. local declarations Algebraic operations on Meddle selections If no explicit Structure in which to look for method given, use Structure of Eval[primary selection]. User selects an operator from methodStructure Check for operators that have non-Object arguments Get Object args, recast them, and apply op Figure out what to do with result caminoItem.object _ result; -- 3/87 caminoItem.object not used ViewerTools.SetContents[caminoItem.nameViewer, name]; -- 3/87 nameViewer not used Conversion Procs PROC [parent: Viewer, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE]; effects: pops up a new text viewer with contents = algebra system value (as a Rope) of primary selection pop up a new text viewer and convert to rope effects: Creates a new text viewer with contents = canonical output form of active seln. make sure there is an active primary selection get viewer & expression associated with primary selection convert expression to rope pop up a new text viewer containing rope effects: Replaces primary selection with expression parsed from linear GetSelection ROPE. local declarations make sure there is an active primary selection get viewer & expression associated with primary selection replace primary selection with exprVal can't do it (parse error), so complain 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: ROPE _ 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]; 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]; }; Header has length 50. make sure there is an active primary selection get viewer & expression associated with primary selection convert expression to rope PutRope: PROC [rope: ROPE] ~ { action: Rope.ActionType ~ {tc.char _ c; TiogaAccess.Put[writer, tc]}; [] _ Rope.Map[base: rope, action: action]; }; convert linear form of expression to internal form convert immutable expression to mutable display form format expression and get box dimensions scale box dimensions from TeX unit sizes to some reasonable size 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 tc.endOfNode _ TRUE; PutRope["X"]; tc.endOfNode _ FALSE; PutLooksRope[" [Artwork node; type 'MeddleArtwork on' to command tool] ", 'n]; -- char looks end of char props TEditInputOps.Break[]; PutRope: PROC [rope: ROPE] ~ { action: Rope.ActionType ~ {tc.char _ c; TiogaAccess.Put[writer, tc]}; [] _ Rope.Map[base: rope, action: action]; }; convert linear form of expression to internal form convert immutable expression to mutable display form format expression and get box dimensions scale box dimensions from TeX unit sizes to some reasonable size 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 tc.endOfNode _ TRUE; PutRope["X"]; tc.endOfNode _ FALSE; PutLooksRope[" [Artwork node; type 'MeddleArtwork on' to command tool] ", 'n]; -- char looks end of char props TEditInputOps.Break[]; effects: Replaces primary selection with expression parsed from linear GetSelection ROPE. local declarations ropeVal: ROPE _ ViewerTools.GetSelectionContents[]; -- get rope from text selection make sure there is an active primary selection get viewer & expression associated with primary selection strip header if present, and convert to DisplayExpr replace primary selection with exprVal, MeddlePtSize value into ScratchPad can't do it (parse error), so complain 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 pointSize: REAL _ TeXToTioga; -- point size to use when rendering MEDDLE expr convert linear form of expression to internal form convert immutable expression to mutable display form format expression and get box dimensions scale box dimensions from TeX unit sizes to some reasonable size 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 tc.endOfNode _ TRUE; PutRope["X"]; tc.endOfNode _ FALSE; PutLooksRope[" [Artwork node; type 'MeddleArtwork on' to command tool] ", 'n]; -- char looks end of char props TEditInputOps.Break[]; Debugging effects: SIGNALS Break to enter the symbolic debugger. Start Code Register a command with the UserExec that will create an instance of this tool. [ ] _ MakeCaminoItem[NIL]; -- and create an instance ÊP똚œ™Icode™Kšœ˜K˜—šŸœ˜#K™KKšœœ ˜K˜(K˜Kšœ™šœ˜Kšœ˜šœ˜Jšœ˜Jšœ˜Kšœ œ˜Kšœ œ˜—Kšœ˜—K˜Kšœ ™ Kšœœ ˜Kšœ˜K˜Kšœ"  ˜-K˜K˜Kšœ™K™K˜Kšœ™Kšœ˜ K˜K˜—šŸœ˜0Kšœ4™4K˜šœ œ˜%K˜K˜ K˜ K˜ Kšœ œ˜Kšœ œ˜Kšœ œ˜—K˜K˜—šŸœ˜,Kšœ=™=K˜Kšœœ ˜@K˜Kšœ7™7Kšœœ€˜–Kšœœs˜ŒK˜šœ˜šœ ˜ Kš œœœœœ˜[K˜—šœ˜Kšœ˜K˜,K˜—˜ K˜K˜,K˜—Kšœ œ˜Kšœœ˜—K˜K˜—šŸœ˜/Kšœ@™@K˜Kšœœ ˜@K˜Kšœ7™7Kšœœo˜†Kšœœ{˜“K˜šœ˜šœ ˜ Kš œœœœœ˜ZK˜—˜ K˜K˜,K˜—˜ K˜K˜,K˜—Kšœ œ˜Kšœœ˜—K˜K˜—šŸœ˜0Kšœ>™>K˜Kšœœ ˜&K˜Kšœ.™.K˜!K™Kšœ™K˜Kšœœ ˜4K˜K˜—šŸœ˜/Kšœ6™6Kšœ©™©Kšœ% 5˜Zšœ œ˜˜ Kšœœ ˜&šœ˜šœ˜Kšœ·œ˜ÃK˜—šœ˜Kšœ=™=šœœ˜'Kšœ8œ˜>K˜Kšœ˜Kšœ˜—Kšœ±œ˜½K˜—šœ˜Kšœ=™=šœœ˜'Kšœ8œ˜>K˜Kšœ˜Kšœ˜—Kšœ±œ˜½K˜—Kšœ-˜4K˜——Kšœ) O˜K˜Kšœ ™ K˜—K˜K˜—šŸœœ œœ˜™>K˜šœ˜šœ˜Kšœ"˜"Kšœ+œ˜1Kšœ+œ˜1Kšœ/œ˜5Kšœ˜ K˜——K˜K˜—šŸœ l˜™Kšœ4™4K™Kšœ˜Kšœ™Kšœ œ ˜>Kšœœ ˜&Kšœ œœœ˜3K˜Kš œœœœœœ ˜RK˜Kšœ3™3K˜$K˜ØK˜Kšœ'™'šœœœœœ,œœ˜Všœœ˜%Kšœœ˜Kšœœ˜ K˜CKšœœ œ5˜kK˜—Kšœ˜—K˜Kšœ%™%K˜HK˜K˜—šŸ œœœ˜.Kšœ!˜!K˜K˜K˜—šŸœ˜KšœC™CK˜Kšœœ ˜'K˜K˜K˜,Kšœ-  ˜MK˜K˜—šŸœ˜Kšœ&™&Kšœ<™™>Kšœ6™6Kšœœ ˜'šœ ˜K˜!K˜K˜"Kšœœ˜—K˜,K˜K˜—šŸœ˜KšœM™MK™Kšœœ ˜'K˜K˜K˜—šŸ œœ˜$Kšœ™KšœJ™JK™Kšœœ ˜BK˜KšœF™FK˜$K˜KšœM™MK˜4Kšœ8˜8K˜Kšœ$™$K˜&K˜K˜—šŸœœ˜!Kšœ>™>K˜˜K˜šœ!˜$K˜K˜K˜K˜9K˜/K˜K˜K˜K˜—K˜—K˜——šŸ)™)šŸœœ˜"Kšœ>™>Kšœ<™™>Kšœ0™0K˜Kšœ™KšœJœ˜NKšœ$œ˜(Kšœœ˜ Kšœ<˜Kšœ6™6Kšœ>™>Kšœ<œ™AKšœ)œ˜-Kšœœ˜Kšœœœ '˜SK˜BKšœV˜VK˜;šœ œ˜Kšœœ8˜Pšœ I˜PKšœ ˜ Kšœ˜Kšœ:˜:K˜—K˜—Kšœ˜"K˜—K˜šŸ œœ˜Kšœ0œ ˜GK˜K˜—šŸœœœ˜;Kšœ>™>Kšœ˜Kšœ˜Kšœ œœ '˜VKšœE˜EKšœ ˜ Kšœ<˜K˜Kšœœ'œ˜BKšœ˜Kšœ˜—Kšœ˜K˜K˜—šŸœœ œœœœœ œœ˜dš œœœœœœ˜™>KšœD™DK˜Kšœ™Kšœœ˜Kš œ œœœœ®˜ÊKšœ œ˜Kšœœœ˜Kšœœ˜Kšœœ˜Kšœœœ˜K˜Kšœ ™ Kšœ œ˜Kšœ œ˜Kšœ œ˜Kšœœ˜Kšœœ˜Kšœ œ˜Kšœ œ˜Kšœœ˜Kšœ œ˜Kšœœ˜Kšœ œ˜Kšœœ˜Kšœœ˜Kšœœ˜Kšœ œ˜K˜š Ÿœœœœœ˜(Kšœ=™=KšœA˜GK˜K˜—Kšœœ ˜'KšœJ˜JKšœœœ˜K˜Kšœ™KšœM˜MK˜Kšœ˜šœ/˜5Kšœ,œ˜2K˜Kšœ˜ K˜—K˜Kšœ<™™>šœC˜Cšœœ˜Kšœ+œ˜1K˜K˜—Kšœ#˜#Kšœ˜Kšœœ˜ Kšœ˜ Kšœ˜—K˜Kšœ-œœ™Cšœœ˜ š œœœ(œœ˜Fš œ œœœ!œ œ˜PKšœœœ˜@Kšœ˜—Kšœ œ?˜NKšœ˜—K˜]K˜—K˜K™š œœœ1œœ˜Ošœœ˜ Kšœ˜Kšœ ˜K˜—Kšœ˜—K˜K˜—š Ÿœœ œ,œœ˜cKšœ™Kšœ™Kšœ™K˜Kšœ™Kšœ!˜!K˜Kšœ3˜3K˜Kšœ(™(K˜+Kšœ˜K˜KšœH™Hšœ œ˜Kšœ,˜,—Kšœ3˜7K˜Kšœ%™%Kšœ˜K˜K˜—š Ÿ œœ œœœœ:˜ŠKšœS™SKšœ™™™KšœW™WKšœ #˜>Kšœ œœœ˜0Kšœœ ˜'Kšœœœ˜Kšœ,œ˜0K˜Kšœ=™=šœC˜Cšœœ˜Kšœ+œ˜1K˜K˜—Kšœ)˜)Kšœ  &˜3Kšœœ˜ Kšœ˜ Kšœ˜—K˜Kšœ-œœ™Cšœœ˜ š œœœ(œœ˜FKšœœœ˜š œ œœœ!œ œ˜PKšœœœœ˜LKšœ˜—šœœœ˜/Kšœ œF˜UK˜—šœ˜Kšœ œ?˜NK˜—Kšœ˜—K˜^K˜K˜—Kšœ ™ š œœœ1œœ˜Ošœœ˜ Kšœ˜KšœOœ˜YKšœ ˜K˜—Kšœ˜—K˜K˜—š Ÿœœ œ,œœ˜fKšœ™Kšœ™Kšœ™KšœQ™QK™K˜Kšœ5˜5K˜KšœM˜MK˜Kšœ(™(K˜+Kšœ˜K˜KšœN™Nšœœ˜Kšœ7˜7—Kšœ/˜3Kšœ˜K˜——šœŸ™"šŸ œœœ˜.KšœL˜RK˜K˜—šŸœœœ˜&KšœE™EKšœ.™.KšœT™TK™=K™Kšœ™Kšœ˜K˜K™Mšœœ œ˜JKšœœ3˜šœœ˜šœœœœ˜#Kš œ œœœœœ 1˜mKšœ˜&—šœ˜ Kšœœ˜ Kšœœ˜ Kšœœ˜Kšœœ˜ šœ˜šœk˜kšœ˜KšœV˜VK˜$K˜$Kšœ˜—Kšœ<˜˜FKšœ'˜'Kšœ œœ0œ ˜UKšœ^˜^Jš œ*œœœ<œ˜¤Kšœ˜K˜—Kšœ ˜ K˜—šŸœ˜+Kšœœ ˜,Kšœ$œ˜DK˜K˜—šŸœ˜/Kšœœ ˜,Kšœ$œ˜EK˜K˜—š Ÿ œœ œ œœœ˜ašœ ˜Kšœ$ T˜x—šœ˜Kšœ'˜'Kšœ œœ0œ ˜UKšœQ˜QKšœ?˜?Jšœ/˜/Jšœ* œœ<œ˜¤J˜Kšœ>™>JšœQ™QJ™Jšœ,˜,J˜—K˜——šŸ™šŸœ˜#Kš œœœœ3œœ™pK˜Kšœi™iK˜Kšœœ˜Kšœœ ˜'Kšœœ˜Kšœœ˜šœœœ ˜&K˜ K˜K˜ Kšœœ˜—šœœ˜'Kšœ8œ˜>K˜Kšœ ˜K˜—K˜BKšœ,™,Kšœpœ˜yK˜WK˜K˜—šŸœ˜%KšœY™YK™Kšœœ˜Kšœœ ˜'Kšœœ˜Kšœœ˜Kšœ œœ˜K˜Kšœ.™.šœœ˜'Kšœ8œ˜>K˜Kšœ ˜&K˜—K˜Kšœ9™9K˜BK˜Kšœ™K˜RK˜Kšœ(™(Kšœfœ˜pK˜$K˜—šŸœ˜'KšœZ™ZK™Kšœ™Kšœ œ( ˜TKšœ$œ˜(Kšœœœ˜Kšœœ˜K˜Kšœ.™.šœœ˜'Kšœ8œ˜>K˜Kšœ ˜&K˜—K˜Kšœ9™9K˜BK˜Kšœkœœ˜~K˜šœœ˜ Kšœ&™&K˜5K˜Kšœ  ˜9K˜—šœ˜Kšœ&™&Kšœ1œ˜7K˜K˜—K˜K˜—šŸœ™"KšœY™YK™Kšœœ™Kšœœ ™'Kšœœ™Kšœœ™Kšœ œœ™K™Kšœ.™.šœœ™'Kšœ8œ™>K™Kšœ ™&K™—K™Kšœ9™9K™BK™Kšœ™K™RK™Kšœ(™(K™ZK™$K™K™—š Ÿ œ œ œœœ˜K˜Kšœœ ˜+K˜—K˜Kšœ9™9Kšœ œ4˜9K˜Kšœ™KšœL˜RK˜K˜K˜—š Ÿ œ œ)œœœœ˜ešœ˜Kšœ ˜ Kšœ ˜ Kšœœœ˜Kšœœ˜ Kšœ œ˜Kšœ œ˜K˜Kšœ ˜ Kšœ˜—šŸœœœ™JšœE™EK•StartOfExpansionT[base: ROPE, start: INT _ 0, len: INT _ 2147483647, action: Rope.ActionType]šœ*™*Kšœ™—šŸ œœœœ˜,Kšœœœ;˜QKšœ˜—K˜Kšœœœ˜Kšœ+œ˜/Kšœœœ˜Kšœ2œœ ˜XK˜Kšœ œ˜+Kš œ œœœœ˜%˜Kšœ2™2—šœuœ˜€Kšœ4™4—˜K˜Kšœ ˜&K˜—K˜Kšœ9™9K˜BK˜Kšœ3™3Kšœzœœ˜ŽK˜šœœ˜ KšœJ™JK˜5KšœA˜AK˜Kšœ  ˜9K˜—šœ˜Kšœ&™&Kšœ1œ˜7K˜K˜—K˜K˜K˜—šŸ œ˜Kšœ}™}K˜KšŸ œœ  <˜VK˜šŸ œœœ)œœœœ˜ešœ˜Kšœ ˜ Kšœ ˜ Kšœœœ˜Kšœœ˜ Kšœ œ˜Kšœ œ˜K˜Kšœ ˜ Kšœ˜—šŸ œœœœ˜,Kšœœœ;˜QKšœ˜—K˜KšŸ œœ  <™VKšœ œ /™NK˜Kšœœœ˜Kšœ+œ˜/Kšœœœ˜Kšœ2œœ ˜XK˜Kš œ œœœœ˜#˜Kšœ2™2—šœ€œ˜‹Kšœ4™4—˜