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
]];
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: REF ← NIL, msg: ROPE ← NIL];
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;
};
SelectFile: TEditInputExtras.CommandClosureProc ~ {
PROC [data: REF ANY, viewer: ViewerClasses.Viewer ← NIL, param: REF ← NIL] RETURNS [recordAtom: BOOL ← TRUE, quit: BOOL ← FALSE];
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: REF ← NIL] RETURNS [recordAtom: BOOL ← TRUE, quit: BOOL ← FALSE];
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: REF ← NIL] RETURNS [recordAtom: BOOL ← TRUE, quit: BOOL ← FALSE];
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: REF ← NIL] RETURNS [recordAtom: BOOL ← TRUE, quit: BOOL ← FALSE];
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: REF ← NIL, msg: ROPE ← NIL];
activeStatsOn ¬ TRUE;
};
ActiveStatsOff: Commander.
CommandProc = {
PROC [cmd: Handle] RETURNS [result: REF ← NIL, msg: ROPE ← NIL];
activeStatsOn ¬ FALSE;
};
ButtonsOnOff: Commander.CommandProc = {
PROC [cmd: Handle] RETURNS [result: REF ← NIL, msg: ROPE ← NIL];
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."];
};
};
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.