<<>> <> <> <> <> <> <> <> DIRECTORY Args, Ascii, Atom, CodeTimer, Commander, Convert, EBEditors, EBTypes, Imager, InputFocus, IO, List, Menus, NodeProps, NodeStyle, NodeStyleOps, PropRegistry, RefTab, Rope, SimpleFeedback, TEditDisplay, TEditDocument, TEditDocumentPrivate, TEditFormat, TEditInput, TEditInputExtras, TEditLocks, TEditPrivate, TEditSelection, TEditSelectionOps, TEditSelectionPrivateExtras, TextEdit, TextEditBogus, TextNode, Tioga, TiogaActive, TiogaMenuOps, TiogaOps, ViewerClasses, ViewerIO, ViewerOps; TiogaActiveImpl: CEDAR PROGRAM IMPORTS Args, CodeTimer, Commander, Convert, EBEditors, Imager, InputFocus, IO, List, Menus, NodeProps, PropRegistry, RefTab, Rope, SimpleFeedback, TEditDisplay, TEditFormat, TEditInput, TEditInputExtras, TEditLocks, TEditPrivate, TEditSelection, TEditSelectionOps, TEditSelectionPrivateExtras, TextEdit, TextEditBogus, TextNode, TiogaMenuOps, TiogaOps, ViewerIO, ViewerOps EXPORTS TiogaActive ~ BEGIN ActiveButton: TYPE ~ EBTypes.ActiveButton; -- REF ANY ActiveDoc: TYPE ~ EBTypes.ActiveDoc; ROPE: TYPE ~ Rope.ROPE; Viewer: TYPE ~ ViewerClasses.Viewer; <> TiogaButton: TYPE ~ REF TiogaButtonRep; TiogaButtonRep: TYPE ~ RECORD [location: Tioga.Location, viewer: Viewer]; Range: TYPE ~ RECORD [node: Tioga.Node, index: INT, nChars: INT]; GetRange: PROC [tiogaButton: TiogaButton] RETURNS [Range] ~ { node: Tioga.Node ~ tiogaButton.location.node; where: INT ~ tiogaButton.location.where; buttonData: REF ~ TextEdit.GetCharProp[node, where, $ButtonData]; first, last: INT ¬ where; FOR i: INT DECREASING IN[0..where) DO IF TextEdit.GetCharProp[node, i, $ButtonData]=buttonData THEN first ¬ i ELSE EXIT; ENDLOOP; FOR i: INT IN(where..TextEdit.Size[node]) DO IF TextEdit.GetCharProp[node, i, $ButtonData]=buttonData THEN last ¬ i ELSE EXIT; ENDLOOP; RETURN[[node: node, index: first, nChars: last-first+1]]; }; TiogaGetRef: EBEditors.GetRefProc ~ { <> tiogaButton: TiogaButton ~ NARROW[button]; loc: Tioga.Location ~ tiogaButton.location; ref ¬ TextEdit.GetCharProp[loc.node, loc.where, key]; IF ref=NIL THEN { -- try inheritance from root node viewer: Viewer ~ NARROW[doc.theDoc]; tdd: TEditDocument.TEditDocumentData ~ NARROW[viewer.data]; ref ¬ TextEdit.GetProp[tdd.text, key]; }; }; TiogaSetRef: EBEditors.SetRefProc ~ { <> tiogaButton: TiogaButton ~ NARROW[button]; range: Range ~ GetRange[tiogaButton]; TextEdit.PutCharProp[range.node, range.index, key, ref, range.nChars]; }; TiogaMapRef: EBEditors.MapRefProc ~ { <> viewer: Viewer ~ NARROW[doc.theDoc]; tdd: TEditDocument.TEditDocumentData ~ NARROW[viewer.data]; IF tdd = NIL THEN RETURN[FALSE]; -- the document as gone away (been destroyed?) FOR node: Tioga.Node ¬ tdd.text, TextNode.StepForward[node] UNTIL node=NIL DO IF node.charProps#NIL THEN { size: INT ¬ TextEdit.Size[node]; newSize: INT ¬ 0; index: INT ¬ 0; WHILE index> index ¬ range.index+range.nChars+newSize-size; -- move to end of button size ¬ newSize; IF aborted THEN RETURN; } ELSE index ¬ index+1; ENDLOOP; }; ENDLOOP; }; ParseFeedback: PROC [rope: ROPE] RETURNS [list: LIST OF REF ¬ NIL] ~ { <> h: IO.STREAM ~ IO.RIS[rope]; tail: LIST OF REF ¬ NIL; DO item: REF ¬ NIL; item ¬ IO.GetRefAny[h ! IO.EndOfStream => CONTINUE]; IF item#NIL THEN list ¬ List.Nconc1[list, item] ELSE EXIT; ENDLOOP; }; TiogaFeedback: EBEditors.FeedbackProc ~ { <> tiogaButton: TiogaButton ~ NARROW[button]; viewer: Viewer ~ NARROW[doc.theDoc]; result: REF ¬ feedback; WITH result SELECT FROM rope: ROPE => result ¬ ParseFeedback[rope]; ENDCASE; IF result = NIL THEN RETURN[NIL]; theButton ¬ tiogaButton; TEditInput.Interpret[viewer, NARROW[result]]; RETURN[result]; }; <> <> <> <> <<};>> <<>> Interpret: PUBLIC PROC [tiogaViewer: Viewer, button: ActiveButton, doc: ActiveDoc, events: LIST OF REF] = { WITH button SELECT FROM tiogaButton: TiogaButton => { tB: TiogaButton ~ NARROW[button]; theButton ¬ tB; }; ENDCASE => theButton ¬ NIL; TEditInput.Interpret[tiogaViewer, events]; }; TiogaGetText: EBEditors.GetTextProc ~ { <> text ¬ GetButtonContents[button]; }; TiogaGetDocName: EBEditors.GetDocNameProc ~ { <> theDoc: Viewer ¬ NARROW[doc.theDoc]; name ¬ theDoc.name; }; tiogaClass: EBEditors.ActiveDocClass ~ NEW[EBEditors.ActiveDocClassObj ¬ [ name: $Tioga, getRef: TiogaGetRef, setRef: TiogaSetRef, mapRef: TiogaMapRef, feedback: TiogaFeedback, getDocName: TiogaGetDocName, getText: TiogaGetText ]]; <> docTable: RefTab.Ref ~ RefTab.Create[]; LookupDoc: PUBLIC PROC [viewer: Viewer] RETURNS [doc: ActiveDoc] ~ { action: RefTab.UpdateAction ~ { IF found THEN doc ¬ NARROW[val] ELSE RETURN[$store, doc ¬ EBEditors.CreateActiveDoc[viewer, tiogaClass]]; }; RefTab.Update[docTable, viewer, action]; }; ButtonsEnabled: PROC [viewer: Viewer] RETURNS [BOOL] ~ { RETURN[viewer.transparentTIP]; }; FindButton: PROC [viewer: Viewer, x, y: INTEGER] RETURNS [button: TiogaButton ¬ NIL] ~ { tdd: TEditDocument.TEditDocumentData ~ NARROW[viewer.data]; DoFindButton: PROC [tSel, refSel: TEditDocument.Selection, rightOfLine: BOOL] ~ { loc: Tioga.Location ~ tSel.start.pos; IF loc.where> <<>> theButton: TiogaButton ¬ NIL; <> <<>> HandleTransparentInput: PROC [self: Viewer, input: LIST OF REF, normalNotify: ViewerClasses.NotifyProc] ~ { event: EBTypes.Event; CodeTimer.StartInt[$TiogaActiveHandleInput, $EmbeddedButtons]; IF activeStatsOn THEN SimpleFeedback.Append[$EmbeddedButtons, oneLiner, $Typescript, "In HandleTransparentInput"]; IF EBEditors.ValidEvent[event ¬ EBEditors.GetEvent[input]] THEN { <> button: TiogaButton ¬ NIL; IF ButtonsEnabled[self] AND mouseHandler=$Any AND EBEditors.MouseAction[event] THEN { m: EBEditors.MousePosition ~ EBEditors.MouseCoords[event]; point: Point ~ ViewerFromScreenPoint[self, [m.mouseX, m.mouseY]]; button ¬ FindButton[self, point.x, point.y]; }; IF button#NIL THEN { CodeTimer.StartInt[$TiogaActiveHandleButton, $EmbeddedButtons]; EBEditors.HandleEvent[event: event, button: button, doc: LookupDoc[self]]; CodeTimer.StopInt[$TiogaActiveHandleButton, $EmbeddedButtons]; } ELSE { -- not an active button, so use the regular tip table result: LIST OF REF ~ EBEditors.ParseEvent[self.tipTable, event]; IF result#NIL THEN normalNotify[self, result]; mouseHandler ¬ $Tioga; -- Tioga handles further actions until mouse buttons go up }; IF EBEditors.MouseAllUp[event] THEN mouseHandler ¬ $Any; } ELSE normalNotify[self, input]; CodeTimer.StopInt[$TiogaActiveHandleInput, $EmbeddedButtons]; }; classText: ViewerClasses.ViewerClass ~ ViewerOps.FetchViewerClass[$Text]; classTypeScript: ViewerClasses.ViewerClass ~ ViewerOps.FetchViewerClass[$Typescript]; ActiveTextNotify: ViewerClasses.NotifyProc ~ { HandleTransparentInput[self, input, TEditPrivate.TEditNotifyProc]; }; ActiveTypeScriptNotify: ViewerClasses.NotifyProc ~ { HandleTransparentInput[self, input, TEditPrivate.TypeScriptNotifyProc]; }; <> << Examples from Hobo, /Ivy/Shoemake/Mesa/BoxCharImpl.mesa GetDataFromLoc: PROC [node: Tioga.Node, where: INT] RETURNS [BoxCharData] ~ { charProps: Atom.PropList ¬ TextEdit.GetCharPropList[node: node, index: where]; boxCharData: BoxCharData ¬ NARROW[charProps.GetPropFromList[$data]]; IF boxCharData = NIL THEN { hoboRope: ROPE ¬ NARROW[charProps.GetPropFromList[$hoboRope]]; IF hoboRope # NIL THEN { boxCharData ¬ NEW[BoxCharDataRep ¬ [node: PutGet.FromRope[hoboRope], screenBox: NIL, printBox: NIL]]; TextEdit.PutCharProp[node: node, index: where, name: $data, value: boxCharData]; }; }; RETURN[boxCharData] }; FormatBoxChar: PROC[class: TEditFormat.CharacterArtworkClass, loc: Tioga.Location, style: NodeStyle.Ref, styleOps: NodeStyleOps.OfStyle] RETURNS[CharacterArtwork] ~ { <> << Returns character artwork for formatted expression.>> << Note that OfStyle: TYPE ~ { screen, print, base }>> charArtwork: CharacterArtwork; boxCharData: BoxCharData ¬ GetDataFromLoc[loc.node, loc.where]; charProps: TextEdit.PropList ¬ TextEdit.GetCharPropList[node: loc.node, index: loc.where]; hoboRope: ROPE ¬ NARROW[charProps.GetPropFromList[$hoboRope]]; boxCharRope: ROPE ¬ NARROW[charProps.GetPropFromList[$BoxChar]]; stippleRope: ROPE ¬ NARROW[charProps.GetPropFromList[$stipple]]; reachRope: ROPE ¬ NARROW[charProps.GetPropFromList[$reach]]; vshiftRope: ROPE ¬ NARROW[charProps.GetPropFromList[$vshift]]; hshiftRope: ROPE ¬ NARROW[charProps.GetPropFromList[$hshift]]; showBoundsRope: ROPE ¬ NARROW[charProps.GetPropFromList[$showBounds]]; fontSize: INTEGER ¬ style.GetFontSizeI[]; font: ImagerFont.Font ¬ TEditFormat.GetFont[style]; charSet: TextEdit.CharSet ¬ 0; char: CHAR ¬ '); chars: ROPE; box: TiogaImager.Box ¬ NIL; stipple: WORD ¬ 50A0H; leftExtent: REAL ¬ 0.0; rightExtent: REAL ¬ 16.0; descent: REAL ¬ 0.0; ascent: REAL ¬ 10.0; extents: ImagerFont.Extents; escapement: ImagerFont.VEC; reach: REAL ¬ 16.0; eqExtents: ImagerFont.Extents ¬ font.RopeBoundingBox["="]; chExtents: ImagerFont.Extents; hscale, vscale: REAL ¬ 1.0; hshift, vshift: REAL ¬ 0.0; showBounds: BOOL ¬ FALSE; [charSet, char] ¬ TextEdit.FetchChar[text: loc.node, index: loc.where]; chars ¬ Rope.Cat[Rope.FromChar[377C], Rope.FromChar[0C+charSet], Rope.FromChar[char]]; stipple ¬ Convert.IntFromRope[stippleRope ! Convert.Error => CONTINUE]; reach ¬ Convert.RealFromRope[reachRope ! Convert.Error => CONTINUE]; hshift ¬ Convert.RealFromRope[hshiftRope ! Convert.Error => CONTINUE]; vshift ¬ Convert.RealFromRope[vshiftRope ! Convert.Error => CONTINUE]; IF showBoundsRope.InlineLength > 0 THEN showBounds ¬ Convert.BoolFromRope[showBoundsRope ! Convert.Error => CONTINUE]; IF boxCharData = NIL THEN { IF boxCharRope = NIL THEN { chExtents ¬ font.RopeBoundingBox[chars]; vscale ¬ MAX[1.0, 2*reach/(chExtents.ascent+chExtents.descent)]; hscale ¬ RealFns.SqRt[RealFns.SqRt[vscale]]; vshift ¬ (eqExtents.ascent+eqExtents.descent)/2 - eqExtents.descent; font ¬ font.Modify[ImagerTransformation.Create[hscale,0,0, 0,vscale,(1-vscale)*vshift]]; extents ¬ font.RopeBoundingBox[chars]; escapement ¬ font.RopeEscapement[chars]; } ELSE { chars ¬ boxCharRope; box ¬ TiogaImager.BoxFromRope[font, chars]; box ¬ box.ModifyBox[ImagerTransformation.Translate[[hshift, vshift]]]; extents ¬ ImagerBox.ExtentsFromBox[box.bounds]; escapement ¬ box.escapement; }; } ELSE { box ¬ BoxInTrain[data: boxCharData, train: [loc: loc, style: style, styleOps: styleOps]]; box ¬ box.ModifyBox[ImagerTransformation.Translate[[hshift, vshift]]]; extents ¬ ImagerBox.ExtentsFromBox[box.bounds]; escapement ¬ box.escapement; }; <> charArtwork ¬ NEW[CharacterArtworkRep ¬ [paint: PaintBoxChar, extents: extents, escapement: escapement, data: NEW[PaintInfoRep ¬ [color: ImagerBackdoor.MakeStipple[stipple: stipple, xor: TRUE], extents: extents, reach: reach, font: font, chars: chars, box: box, showBounds: showBounds]]]]; RETURN[charArtwork]; }; PaintBoxChar: PROC [charArtwork: CharacterArtwork, context: Imager.Context] ~ { paintInfo: PaintInfo ~ NARROW[charArtwork.data]; context.Move[]; IF paintInfo.box = NIL THEN { context.SetFont[paintInfo.font]; context.ShowRope[paintInfo.chars]; } ELSE { IF paintInfo.showBounds THEN { DoPaintBounds: PROC ~ { context.SetStrokeWidth[1.0]; context.SetGray[0.5]; context.MaskStrokeTrajectory[trajectory: ImagerPath.LineToX[ ImagerPath.LineToY[ ImagerPath.LineToX[ ImagerPath.LineToY[ ImagerPath.MoveTo[ [paintInfo.box.bounds.xmin, paintInfo.box.bounds.ymin]], paintInfo.box.bounds.ymax], paintInfo.box.bounds.xmax], paintInfo.box.bounds.ymin], paintInfo.box.bounds.xmin]]; }; Imager.DoSaveAll[context, DoPaintBounds]; }; context.SetFont[paintInfo.font]; TiogaImager.Render[paintInfo.box, context, [0.0, 0.0]]; }; }; >> FormatButton: TEditFormat.CharacterFormatProc ~ { size: INTEGER ¬ 10; RETURN[NEW[TEditFormat.CharacterArtworkRep ¬ [ paint: PaintButton, extents: [0, size+2, 1, size+1], escapement: [size+3, 0], amplified: FALSE, data: NEW[INTEGER ¬ size] ]]]; }; PaintButton: PROC [artwork: TEditFormat.CharacterArtwork, context: Imager.Context] ~ { data: REF INTEGER ~ NARROW[artwork.data]; size: INTEGER ~ data­; context.Trans[]; context.SetGray[1]; context.MaskRectangleI[0, -1, size+2, size+2]; context.SetGray[0.5]; context.MaskRectangleI[1, 0, size, size]; }; buttonArtworkClass: TEditFormat.CharacterArtworkClass ~ NEW[TEditFormat.CharacterArtworkClassRep ¬ [ name: $Button, format: FormatButton, data: NIL ]]; <> ReadButtonData: NodeProps.ReadSpecsProc ~ { RETURN[EBEditors.ButtonDataFromRope[specs, FALSE, NIL, NIL]]; }; WriteButtonData: NodeProps.WriteSpecsProc ~ { RETURN[WITH value SELECT FROM rope: ROPE => rope, ENDCASE => EBEditors.RopeFromButtonData[value]]; }; CopyButtonData: NodeProps.CopyInfoProc ~ { << PROC [name: ATOM, value: REF] RETURNS [new: REF];>> <> WITH value SELECT FROM rope: ROPE => new ¬ rope; ENDCASE => new ¬ EBEditors.ButtonDataFromRope[EBEditors.RopeFromButtonData[value]]; }; <> ActivityCommand: TEditInputExtras.CommandClosureProc ~ { SELECT data FROM $On => viewer.transparentTIP ¬ TRUE; $Off => viewer.transparentTIP ¬ FALSE; ENDCASE; }; GetButtonContents: PUBLIC PROC [button: ActiveButton] RETURNS [ROPE] ~ { WITH button SELECT FROM tiogaButton: TiogaButton => { range: Range ~ GetRange[tiogaButton]; RETURN[Rope.Substr[TextEditBogus.GetRope[range.node], range.index, range.nChars]]; }; ENDCASE; RETURN[NIL]; }; SelectButton: PROC [button: TiogaButton] ~ { IF button#NIL THEN { range: Range ~ GetRange[button]; tSel: TEditDocument.Selection ~ TEditSelection.Alloc[]; tSel.viewer ¬ button.viewer; tSel.data ¬ NARROW[tSel.viewer.data]; tSel.start.pos ¬ [range.node, range.index]; tSel.end.pos ¬ [range.node, range.index+range.nChars-1]; tSel.granularity ¬ word; tSel.punctuation ¬ none; TEditSelection.MakeSelection[tSel, primary]; TEditSelection.Free[tSel] }; }; savedSelection: TEditDocument.Selection ¬ TEditSelection.Create[]; savedSelectionEmpty: BOOL ¬ FALSE; savedOwner: Viewer; savedInfo: REF; SelectTiogaFile: Commander.CommandProc = { <> nameArg: Args.Arg; name: ROPE; namedViewer: Viewer; [nameArg] ¬ Args.ArgsGet[cmd, "%s" ! Args.Error => { cmd.err.PutRope["please specify a file name\n"]; GOTO failed}]; IF NOT nameArg.ok OR nameArg.rope = NIL THEN RETURN; namedViewer ¬ ViewerOps.FindViewer[nameArg.rope]; IF namedViewer = NIL THEN { TEditSelection.KillSelection[]; -- so subsequent operations will fail RETURN; }; BEGIN root, firstnode: Tioga.Node; tSel: TEditDocument.Selection ~ TEditSelection.Alloc[]; tSel.viewer ¬ namedViewer; tSel.data ¬ NARROW[tSel.viewer.data]; root ¬ tSel.data.text; firstnode ¬ TextNode.FirstChild[root]; tSel.start.pos ¬ [firstnode, 0]; tSel.end.pos ¬ [firstnode, 0]; tSel.granularity ¬ point; tSel.punctuation ¬ none; TEditSelection.MakeSelection[tSel, primary]; TEditSelection.Free[tSel]; END; EXITS failed => NULL }; SelectFile: TEditInputExtras.CommandClosureProc ~ { <> name: ROPE; namedViewer: Viewer; WITH param SELECT FROM r: ROPE => name ¬ r; ENDCASE => RETURN; IF name = NIL THEN RETURN; namedViewer ¬ ViewerOps.FindViewer[name]; IF namedViewer = NIL THEN { TEditSelection.KillSelection[]; -- so subsequent operations will fail RETURN; }; BEGIN root, firstnode: Tioga.Node; tSel: TEditDocument.Selection ~ TEditSelection.Alloc[]; tSel.viewer ¬ namedViewer; tSel.data ¬ NARROW[tSel.viewer.data]; root ¬ tSel.data.text; firstnode ¬ TextNode.FirstChild[root]; tSel.start.pos ¬ [firstnode, 0]; tSel.end.pos ¬ [firstnode, 0]; tSel.granularity ¬ point; tSel.punctuation ¬ none; TEditSelection.MakeSelection[tSel, primary]; TEditSelection.Free[tSel]; END; }; ButtonCommand: TEditInputExtras.CommandClosureProc ~ { button: TiogaButton ~ theButton; SELECT data FROM $Select => SelectButton[button]; $Start => { savedFocus: InputFocus.Focus ¬ InputFocus.GetInputFocus[]; -- careful, savedFocus is mutable savedOwner ¬ savedFocus.owner; savedInfo ¬ savedFocus.info; <> <> IF savedOwner # NIL AND (savedOwner.class.flavor = $Text OR savedOwner.class.flavor = $Typescript) THEN { savedSelectionEmpty ¬ FALSE; IF TEditSelection.pSel = NIL THEN TEditSelection.Copy[source: TEditSelection.nilSel, dest: savedSelection] ELSE TEditSelection.Copy[source: TEditSelection.pSel, dest: savedSelection]; <> } ELSE { <> savedSelectionEmpty ¬ TRUE; TEditSelection.Copy[source: TEditSelection.nilSel, dest: savedSelection]; }; SelectButton[button]; }; $End => { IF savedSelectionEmpty THEN { <> InputFocus.SetInputFocus[self: savedOwner, info: savedInfo]; } ELSE { IF TEditInput.CheckSelection[savedSelection] THEN TEditSelection.MakeSelection[selection: primary, new: savedSelection]; <> }; }; ENDCASE; }; SearchCommand: TEditInputExtras.CommandClosureProc ~ { <> <> search: ROPE; inputFocusViewer: Viewer; WITH param SELECT FROM r: ROPE => search ¬ r; ENDCASE => RETURN; IF search = NIL THEN RETURN; inputFocusViewer ¬ IF TEditSelection.pSel = NIL THEN NIL ELSE TEditSelection.pSel.viewer; IF inputFocusViewer = NIL THEN RETURN; WITH inputFocusViewer.data SELECT FROM ntdd: TEditDocument.TEditDocumentData => { <> loc: Tioga.Location ¬ TextNode.LocWithin[ntdd.text, 0]; sel: TEditDocument.Selection ¬ NIL; IF Rope.Match["|*", search] THEN { <> pos: INT ¬ Convert.IntFromRope[Rope.Flatten[search, 1] ! Convert.Error => GO TO faulty]; nloc: Tioga.Location ¬ TextNode.LocWithin[n: ntdd.text, count: pos, skipCommentNodes: FALSE]; <<[] _ PositionViewerInternal[inputFocusViewer, nloc];>> TEditSelectionOps.ShowGivenPosition[viewer: inputFocusViewer, pos: pos, skipCommentNodes: FALSE]; EXITS faulty => {}; } ELSE { <> <> TEditSelection.FindRope[ viewer: inputFocusViewer, rope: search, case: TRUE, word: TRUE, def: FALSE, id: feedback]; <> <> <> <> <> }; <> }; ENDCASE; <> }; PositionHistory: TYPE = TEditDocumentPrivate.PositionHistory; PositionViewerInternal: PROC [viewer: Viewer, loc: Tioga.Location] RETURNS [ok: BOOL ¬ FALSE] = { <> CheckPosition: PROC [viewer: Viewer, loc: Tioga.Location] RETURNS [good: BOOL, goodloc: Tioga.Location] = { root, node, t1: Tioga.Node; tdd: TEditDocument.TEditDocumentData; IF viewer=NIL OR viewer.destroyed OR (node ¬ loc.node)=NIL THEN GOTO Failed; IF (tdd ¬ NARROW[viewer.data]) = NIL THEN GOTO Failed; IF (root ¬ tdd.text)=NIL THEN GOTO Failed; IF TextNode.Root[node] # root THEN GOTO Failed; -- make sure still in the tree IF (t1 ¬ node)=NIL OR loc.where NOT IN [0..TextEdit.Size[t1]] THEN RETURN [TRUE, [node,0]]; RETURN [TRUE, loc]; EXITS Failed => RETURN [FALSE, Tioga.nullLocation]; }; WITH viewer.data SELECT FROM tdd: TEditDocument.TEditDocumentData => { node: Tioga.Node; [ok, loc] ¬ CheckPosition[viewer, loc]; IF ok THEN { <> IF (node ¬ loc.node) # NIL THEN { <> where: INT ¬ MAX[0, MIN[loc.where, TextEdit.Size[node]-1]]; backStop: INT ¬ MAX[0, where-300]; UNTIL where<=backStop OR (SELECT Rope.Fetch[node.rope, where-1] FROM Ascii.CR, Ascii.LF => TRUE, ENDCASE => FALSE) DO where ¬ where - 1; ENDLOOP; loc.where ¬ where; }; TEditDisplay.EstablishLine[tdd, loc]; }; }; ENDCASE; }; <> <> <> <> <> <> <> <> <> <<[] _ TEditDocument.SpinAndLock[tdd, "RememberCurrentPosition"];>> <> <> <> <> <<};>> <<>> ReplaceText: TEditInputExtras.CommandClosureProc ~ { <> <> newSel: TEditDocument.Selection; startPos, endPos: Tioga.Location; root: Tioga.Node; looks: Tioga.Looks; propList: Tioga.PropList; start: INT ¬ 0; newText: ROPE; WITH param SELECT FROM r: ROPE => newText ¬ r; ENDCASE => RETURN; TEditSelection.LockSel[primary, "ReplaceTextCommand"]; startPos ¬ TEditSelection.pSel.start.pos; endPos ¬ TEditSelection.pSel.end.pos; IF startPos.node # endPos.node THEN { TEditSelection.UnlockSel[primary]; RETURN; -- general spans not yet implemented }; root ¬ TEditSelection.SelectionRoot[TEditSelection.pSel]; [] ¬ TEditLocks.Lock[root, "ReplaceTextCommand", read]; newSel ¬ TEditSelection.Alloc[]; TEditSelection.Copy[source: TEditSelection.pSel, dest: newSel]; IF startPos.where # Tioga.NodeItself THEN start ¬ startPos.where; propList ¬ TextEdit.GetCharPropList[startPos.node, start]; looks ¬ TextEdit.FetchLooks[startPos.node, start]; TEditSelection.UnlockDocAndPSel[root]; TiogaOps.Delete[]; TiogaOps.InsertRope[newText]; newSel.end.pos.where ¬ newSel.start.pos.where + Rope.Length[newText]-1; TEditSelection.MakeSelection[newSel, primary]; TEditSelection.Free[newSel]; TEditSelection.LockSel[primary, "ReplaceTextCommand"]; root ¬ TEditSelection.SelectionRoot[TEditSelection.pSel]; [] ¬ TEditLocks.Lock[root, "ReplaceTextCommand"]; TextEdit.PutCharPropList[node: newSel.start.pos.node, index: newSel.start.pos.where, propList: propList, nChars: Rope.Length[newText], event: TEditInput.CurrentEvent[], root: root]; TextEdit.ChangeLooks[root: root, text: newSel.start.pos.node, remove: Tioga.allLooks, add: looks, start: newSel.start.pos.where, len: Rope.Length[newText], event: TEditInput.CurrentEvent[]]; TEditSelection.UnlockDocAndPSel[root]; }; SetPostfix: TEditInputExtras.CommandClosureProc ~ { <> newPostfix: ROPE; propClass: PropRegistry.RegistryClass; setProp: PropRegistry.PropSetProc; WITH param SELECT FROM r: ROPE => newPostfix ¬ r; ENDCASE => RETURN; propClass ¬ PropRegistry.GetRegistered[viewer.class.flavor]; IF propClass = NIL THEN RETURN; setProp ¬ propClass.setProp; setProp[key: $Postfix, doc: viewer, hint: NIL, prop: newPostfix, edited: TRUE]; }; InstallMenuButton: PROC [name: ROPE, proc: Menus.MenuProc] ~ { <> tiogaMenu: ViewerClasses.Menu ~ TiogaMenuOps.tiogaMenu; old: Menus.MenuEntry ~ Menus.FindEntry[menu: tiogaMenu, entryName: name]; new: Menus.MenuEntry ~ Menus.CreateEntry[name: name, proc: proc]; IF old = NIL THEN Menus.AppendMenuEntry[tiogaMenu, new] ELSE Menus.ReplaceMenuEntry[tiogaMenu, old, new]; }; ActivityMenuProc: Menus.MenuProc ~ { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift: BOOL, control: BOOL]>> viewer: ViewerClasses.Viewer ~ NARROW[parent]; atom: ATOM ~ SELECT mouseButton FROM red => $ActivityOn, ENDCASE => $ActivityOff; TEditInput.InterpretAtom[viewer, atom]; }; activeStatsOn: BOOL ¬ FALSE; ActiveStatsOn: Commander.CommandProc = { <> activeStatsOn ¬ TRUE; }; ActiveStatsOff: Commander.CommandProc = { <> activeStatsOn ¬ FALSE; }; ButtonsOnOff: Commander.CommandProc = { <> viewer: ViewerClasses.Viewer; onOff, quiet: Args.Arg; ok: BOOL ¬ TRUE; <> [onOff, quiet] ¬ Args.ArgsGet[cmd, "[s-quiet[b" !Args.Error => { cmd.err.PutF1["Buttons: %g\n", [rope[reason]]]; GOTO failed}]; viewer ¬ ViewerIO.GetViewerFromStream[cmd.out]; IF viewer#NIL THEN { IF NOT onOff.ok THEN { IF NOT quiet.ok OR NOT quiet.bool THEN PrintActivity[cmd.out, viewer] } ELSE { IF Rope.Equal[onOff.rope, "on"] THEN viewer.transparentTIP ¬ TRUE ELSE IF Rope.Equal[onOff.rope, "off"] THEN viewer.transparentTIP ¬ FALSE ELSE cmd.out.PutRope["Buttons: please specify on or off\n"]; IF NOT quiet.ok OR NOT quiet.bool THEN PrintActivity[cmd.out, viewer] }; } ELSE { cmd.out.PutRope["Can't change button activity. This typescript is not a Viewer."]; }; EXITS failed => NULL }; PrintActivity: PROC [f: IO.STREAM, viewer: ViewerClasses.Viewer] = { IF viewer = NIL THEN RETURN; IF viewer.transparentTIP THEN f.PutRope["Buttons are on\n"] ELSE f.PutRope["Buttons are off\n"]; }; <> NodeProps.Register[$ButtonData, ReadButtonData, WriteButtonData, CopyButtonData]; TEditFormat.RegisterCharacterArtwork[buttonArtworkClass]; TEditInputExtras.RegisterClosure[[$ActivityOn, ActivityCommand, $On]]; TEditInputExtras.RegisterClosure[[$ActivityOff, ActivityCommand, $Off]]; TEditInputExtras.RegisterClosure[[$SelectFile, SelectFile, NIL]]; TEditInputExtras.RegisterClosure[[$SelectButton, ButtonCommand, $Select]]; TEditInputExtras.RegisterClosure[[$StartButton, ButtonCommand, $Start]]; TEditInputExtras.RegisterClosure[[$BeginButton, ButtonCommand, $Start]]; TEditInputExtras.RegisterClosure[[$EndButton, ButtonCommand, $End]]; TEditInputExtras.RegisterClosure[[$ReplaceText, ReplaceText, NIL]]; TEditInputExtras.RegisterClosure[[$Search, SearchCommand, NIL]]; TEditInputExtras.RegisterClosure[[$SetPostfix, SetPostfix, NIL]]; <> classText.notify ¬ ActiveTextNotify; classTypeScript.notify ¬ ActiveTypeScriptNotify; InstallMenuButton["", ActivityMenuProc]; Commander.Register[key: "activeStatsOn", proc: ActiveStatsOn, doc: "turns on statistics in TiogaActive"]; Commander.Register[key: "activeStatsOff", proc: ActiveStatsOff, doc: "turns off statistics in TiogaActive"]; Commander.Register[key: "Buttons", proc: ButtonsOnOff, doc: "Buttons \n turns embedded buttons on and off in this typescript."]; Commander.Register[key: "SelectTiogaFile", proc: SelectTiogaFile, doc: "SelectTiogaFile \n puts the input focus in the named Tioga file (if it is open)"]; END.