TiogaActiveImpl.mesa
Copyright Ó 1989, 1990, 1991, 1992 by Xerox Corporation. All rights reserved.
Goodisman, August 2, 1989 10:11:12 pm PDT
Kenneth A. Pier, November 10, 1992 10:34 am PST
Bier, August 22, 1991 7:10 pm PDT
Doug Wyatt, April 23, 1992 11:52 am PDT
Contents: Routines for managing buttons in Tioga and for communicating with the EmbeddedButtons package.
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;
ActiveDoc class
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 ~ {
PROC [key: ATOM, button: ActiveButton, doc: ActiveDoc] RETURNS [ref: REF];
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 ~ {
PROC [key: ATOM, button: ActiveButton, doc: ActiveDoc, ref: REF];
tiogaButton: TiogaButton ~ NARROW[button];
range: Range ~ GetRange[tiogaButton];
TextEdit.PutCharProp[range.node, range.index, key, ref, range.nChars];
};
TiogaMapRef: EBEditors.MapRefProc ~ {
PROC [doc: ActiveDoc, mapProc: EachButtonProc] RETURNS [aborted: BOOL ← FALSE];
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<size DO
buttonData: REF ~ TextEdit.GetCharProp[node, index, $ButtonData];
IF buttonData#NIL THEN {
tiogaButton: TiogaButton ~ NEW[TiogaButtonRep ¬ [
location: [node: node, where: index], viewer: viewer]];
range: Range ~ GetRange[tiogaButton];
aborted ¬ mapProc[tiogaButton, doc];
newSize ¬ TextEdit.Size[node];
Assume that the only object in this node that has changed size is the button itself.
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] ~ {
based on EditToolOpsImpl.GetOps
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 ~ {
PROC[button: ActiveButton, doc: ActiveDoc, feedback: REF] RETURNS [REF];
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] = {
tiogaButton: TiogaButton ~ NARROW[button];
theButton ¬ tiogaButton;
TEditInput.Interpret[tiogaViewer, events];
};
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 ~ {
PROC [button: ActiveButton, doc: ActiveDoc] RETURNS [text: ROPE];
text ¬ GetButtonContents[button];
};
TiogaGetDocName: EBEditors.GetDocNameProc ~ {
PROC [doc: ActiveDoc] RETURNS [name: ROPE];
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
]];
Notify procedures
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<TextEdit.Size[loc.node] AND
TextEdit.GetCharProp[loc.node, loc.where, $ButtonData]#NIL
THEN button ¬ NEW[TiogaButtonRep ¬ [location: loc, viewer: viewer]];
};
CodeTimer.StartInt[$TiogaActiveFindButton, $EmbeddedButtons];
TEditSelectionPrivateExtras.DoSelect[DoFindButton, viewer, tdd, x, viewer.ch-y, primary];
CodeTimer.StopInt[$TiogaActiveFindButton, $EmbeddedButtons];
};
Point: TYPE ~ RECORD [x, y: INTEGER];
ViewerFromScreenPoint: PROC [v: ViewerClasses.Viewer, s: Point] RETURNS [Point] ~ {
parent: ViewerClasses.Viewer ~ v.parent;
IF parent=NIL THEN RETURN[[(s.x-v.wx)-v.cx, (s.y-v.wy)-v.cy]]
ELSE {
p: Point ~ ViewerFromScreenPoint[parent, s];
topDown: BOOL ~ parent.class.topDownCoordSys;
wx: INTEGER ~ v.wx;
wy: INTEGER ~ IF topDown THEN parent.ch-(v.wy+v.wh) ELSE v.wy;
RETURN[[(p.x-wx)-v.cx, (p.y-wy)-v.cy]];
};
};
mouseHandler: {Any, Tioga} ¬ Any;
state variable used by HandleTransparentInput
theButton: TiogaButton ¬ NIL;
most recently activated button
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 {
input came from a transparent TIP table (because self.transparentTIP=TRUE)
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];
};
Character Artwork
<< 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] ~ {
effects: Formats math expression artwork represented by ROPE at loc.
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;
};
create artwork char
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
]];
Property support
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];
If ButtonData has been parsed, unparse and reparse so that the document will be in the same state as it will be when filed out and filed in.
WITH value SELECT FROM
rope: ROPE => new ¬ rope;
ENDCASE => new ¬
EBEditors.ButtonDataFromRope[EBEditors.RopeFromButtonData[value]];
};
Tioga commands
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 = {
PROC [cmd: Handle] RETURNS [result: REFNIL, msg: ROPENIL];
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 ~ {
PROC [data: REF ANY, viewer: ViewerClasses.Viewer ← NIL, param: REFNIL] RETURNS [recordAtom: BOOLTRUE, quit: BOOLFALSE];
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 TEditSelection.pSel=NIL OR TEditSelection.IsDown[primary]
IF TEditSelection.pSel#NIL
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];
Feedback.PutFByName[$EmbeddedButtons, oneLiner, $Feedback, "BeginButton Tioga selection in %g", [atom[IF savedOwner = NIL THEN $NIL ELSE savedOwner.class.flavor]] ];
}
ELSE {
Feedback.PutFByName[$EmbeddedButtons, oneLiner, $Feedback, "BeginButton input focus = %g", [atom[IF savedOwner = NIL THEN $NIL ELSE savedOwner.class.flavor]] ];
savedSelectionEmpty ¬ TRUE;
TEditSelection.Copy[source: TEditSelection.nilSel, dest: savedSelection];
};
SelectButton[button];
};
$End => {
IF savedSelectionEmpty THEN {
Feedback.PutFByName[$EmbeddedButtons, oneLiner, $Feedback, "EndButton input focus = %g", [atom[IF savedOwner = NIL THEN $NIL ELSE savedOwner.class.flavor]] ];
InputFocus.SetInputFocus[self: savedOwner, info: savedInfo];
}
ELSE {
IF TEditInput.CheckSelection[savedSelection]
THEN TEditSelection.MakeSelection[selection: primary, new: savedSelection];
Feedback.PutFByName[$EmbeddedButtons, oneLiner, $Feedback, "EndButton Tioga selection in %g", [atom[IF savedOwner = NIL THEN $NIL ELSE savedOwner.class.flavor]] ];
};
};
ENDCASE;
};
SearchCommand: TEditInputExtras.CommandClosureProc ~ {
PROC [data: REF, viewer: ViewerClasses.Viewer ← NIL, param: REFNIL] RETURNS [recordAtom: BOOLTRUE, quit: BOOLFALSE];
Copied from TEditDocuments2Impl.CreateAndFillTiogaViewer.
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 => {
We need to perform a search for the given definition.
loc: Tioga.Location ¬ TextNode.LocWithin[ntdd.text, 0];
sel: TEditDocument.Selection ¬ NIL;
IF Rope.Match["|*", search]
THEN {
This is a position spec to parse
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 {
This is a definition to search for
TEditDisplay.EstablishLine[ntdd, loc];
TEditSelection.FindRope[
viewer: inputFocusViewer, rope: search, case: TRUE, word: TRUE, def: FALSE, id: feedback];
sel ← TEditSelection.fSel;
IF sel # NIL AND sel.viewer = inputFocusViewer THEN
capture the location found and establish it as the place to display
loc ← sel.start.pos;
TEditDisplay.EstablishLine[ntdd, loc];
};
RememberCurrentPosition[inputFocusViewer];
};
ENDCASE;
ViewerForkers.ForkPaint[inputFocusViewer, client];
};
PositionHistory: TYPE = TEditDocumentPrivate.PositionHistory;
PositionViewerInternal: PROC [viewer: Viewer, loc: Tioga.Location] RETURNS [ok: BOOL ¬ FALSE] = {
Copied from TEditDocuments2Impl.PositionViewerInternal.
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 {
RememberCurrentPosition[viewer];
IF (node ¬ loc.node) # NIL THEN {
backup to line start
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;
};
RememberCurrentPosition: PUBLIC PROC [viewer: Viewer] = {
Copied from TEditDocuments2Impl.RememberCurrentPosition
tdd: TEditDocument.TEditDocumentData ← NARROW[viewer.data];
prop: REF PositionHistory ← NARROW[ViewerOps.FetchProp[viewer, $PositionHistory]];
loc: TextNode.Location;
IF tdd=NIL THEN RETURN;
IF prop = NIL THEN {
prop ← NEW[PositionHistory];
ViewerOps.AddProp[viewer, $PositionHistory, prop] };
[] ← TEditDocument.SpinAndLock[tdd, "RememberCurrentPosition"];
loc ← tdd.lineTable.lines[0].pos;
TEditDocument.Unlock[tdd];
IF loc = prop.pos THEN RETURN;
prop.prev ← prop.pos; prop.pos ← loc;
};
ReplaceText: TEditInputExtras.CommandClosureProc ~ {
PROC [data: REF ANY, viewer: ViewerClasses.Viewer ← NIL, param: REFNIL] RETURNS [recordAtom: BOOLTRUE, quit: BOOLFALSE];
Get the looks, and properties of the selected characters.
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 ~ {
PROC [data: REF ANY, viewer: ViewerClasses.Viewer ← NIL, param: REFNIL] RETURNS [recordAtom: BOOLTRUE, quit: BOOLFALSE];
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] ~ {
stolen from EditorComfortsAImpl
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 = {
PROC [cmd: Handle] RETURNS [result: REFNIL, msg: ROPENIL];
activeStatsOn ¬ TRUE;
};
ActiveStatsOff: Commander.CommandProc = {
PROC [cmd: Handle] RETURNS [result: REFNIL, msg: ROPENIL];
activeStatsOn ¬ FALSE;
};
ButtonsOnOff: Commander.CommandProc = {
PROC [cmd: Handle] RETURNS [result: REFNIL, msg: ROPENIL];
viewer: ViewerClasses.Viewer;
onOff, quiet: Args.Arg;
ok: BOOL ¬ TRUE;
onOff ← CommanderOps.NextArgument[cmd];
[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"];
};
Initialization
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]];
TEditInputPrivate.SetNotifyProc[ActiveTextNotifyProc];
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 <on|off>\n turns embedded buttons on and off in this typescript."];
Commander.Register[key: "SelectTiogaFile", proc: SelectTiogaFile, doc: "SelectTiogaFile <filename>\n puts the input focus in the named Tioga file (if it is open)"];
END.