ButtonApplicationsImpl.mesa
Copyright Ó 1989, 1990, 1991, 1992 by Xerox Corporation. All rights reserved.
Goodisman, August 11, 1989 5:29:03 pm PDT
Spreitzer, May 7, 1990 12:38 pm PDT
Kenneth A. Pier, October 31, 1990 2:16 pm PST
Bier, July 11, 1991 5:31 pm PDT
Doug Wyatt, April 14, 1992 1:22 pm PDT
Willie-s, May 12, 1992 2:40 pm PDT
Contents: The implementations of some applications that register themselves with EmbeddedButtons. These applications are current included:
$Tioga -- Sends a list of Tioga events (i.e., Tioga macros) to the Tioga input handler
$Gargoyle
$CommandTool
$MessageWindow
$Buttonizer
$ButtonizerButtonizer
DIRECTORY
Atom, Commander, CommanderOps, Convert, EBTypes, EditedStream, EmbeddedButtons, Feedback, FeedbackOps, FeedbackTypes, FileNames, InputFocus, IO, List, Menus, MessageWindow, NodeProps, ProcessProps, PropRegistry, Rope, RuntimeError, SimpleFeedback, TEditDocument, TEditInput, TEditInputOps, TEditLocks, TEditOps, TEditSelection, TextEdit, TextNode, TiogaActive, TiogaOps, TypeScript, ViewerClasses, ViewerIO, ViewerTools;
ButtonApplicationsImpl: CEDAR PROGRAM
IMPORTS Atom, CommanderOps, Convert, EditedStream, EmbeddedButtons, Feedback, FeedbackOps, FileNames, InputFocus, IO, List, Menus, MessageWindow, NodeProps, ProcessProps, PropRegistry, Rope, RuntimeError, SimpleFeedback, TEditInput, TEditInputOps, TEditLocks, TEditOps, TEditSelection, TextEdit, TextNode, TiogaActive, TiogaOps, TypeScript, ViewerIO, ViewerTools
= BEGIN
ActiveButton: TYPE = EBTypes.ActiveButton;
ActiveDoc: TYPE = EBTypes.ActiveDoc;
ButtonInfo: TYPE = EBTypes.ButtonInfo;
RegisteredNotifyProc: TYPE = EmbeddedButtons.RegisteredNotifyProc;
ROPE: TYPE = Rope.ROPE;
Viewer: TYPE = ViewerClasses.Viewer;
TiogaHandler: RegisteredNotifyProc = {
PROC[events: LIST OF REF ANY, buttonInfo: ButtonInfo];
events will, for the most part, be a list of Tioga actions, such as (1 ApplyLook). However, if the combination $EBApplications $GetKeyValue $<some value name> occurs, the named value is retrieved from the active document. This allows a button to base its operation on any of the values in the docuent.
viewer: ViewerClasses.Viewer;
inputFocus: InputFocus.Focus;
events ¬ ProcessEvents[events, buttonInfo.doc];
inputFocus ¬ InputFocus.GetInputFocus[];
IF inputFocus # NIL THEN {
viewer ¬ inputFocus.owner;
IF viewer # NIL AND (viewer.class.flavor = $Text OR viewer.class.flavor = $Typescript) THEN {
TiogaOps.Interpret[viewer, events];
TiogaActive.Interpret[viewer, buttonInfo.button, buttonInfo.doc, events];
}
ELSE SimpleFeedback.Append[routerName: $EmbeddedButtons, msgType: oneLiner, msgClass: $UserError, msg: "Tioga message handler: input focus not in a Tioga viewer."];
};
};
SyntaxError: PUBLIC SIGNAL[msg: Rope.ROPE] = CODE;
ProcessEvents: PROC [events: LIST OF REF ANY, doc: ActiveDoc] RETURNS [newEvents: LIST OF REF ANY] = {
z: LIST OF REF ANY;
l: LIST OF REF ANY;
newEvents ¬ LIST[NIL];
z ¬ newEvents;
l ¬ events;
DO
IF l = NIL THEN EXIT;
IF l.first # $EBApplications THEN {
z.rest ¬ LIST[l.first];
z ¬ z.rest;
l ¬ l.rest;
}
ELSE {
l ¬ l.rest;
IF l.first = $GetKeyValue THEN l ¬ GetKeyValue[l, doc]
ELSE
EmbeddedButtons.Error[Rope.Concat["Embedded buttons applications handler: Unknown function: ", Atom.GetPName[NARROW[l.first]]], Rope.Cat["The Embedded buttons applications handler encountered an unknown function following an $EBApplications atom: ", Atom.GetPName[NARROW[l.first]], ". The button press will be ignored."]];
};
ENDLOOP;
newEvents ¬ newEvents.rest;
};
GetKeyValue: PROC [l: LIST OF REF ANY, doc: ActiveDoc] RETURNS [newEvents: LIST OF REF ANY ¬ NIL] = {
Format:
$GetKeyValue <key>
val: REF;
key: ATOM;
Get key
l ¬ l.rest;
IF ~ISTYPE[l.first, ATOM] THEN {EmbeddedButtons.Error["Embedded buttons applications handler: Invalid key name in $GetKeyValue", "The Embedded buttons applications handler encountered an unknown object while expecting an ATOM. This occurred while processing a $EBApplications $GetKeyValue."]; RETURN;};
key ¬ NARROW[l.first];
Get the value for that key
val ¬ EmbeddedButtons.GetValue[key, doc];
newEvents ¬ LIST[val];
newEvents.rest ¬ l.rest;
};
MessageWindowHandler: EmbeddedButtons.RegisteredNotifyProc = {
PROC[events: LIST OF REF ANY, buttonInfo: ButtonInfo];
PrintRef: PROC [item: REF] = {
WITH item SELECT FROM
atom: ATOM => eventRope ¬ Rope.Cat[eventRope, " ", Convert.RopeFromAtom[atom]];
rope: Rope.ROPE => eventRope ¬ Rope.Cat[eventRope, " ", Convert.RopeFromRope[rope]];
refInt: REF INT => eventRope ¬ Rope.Cat[eventRope, " ", Convert.RopeFromInt[refInt­]];
refCard: REF CARD => eventRope ¬ Rope.Cat[eventRope, " ", Convert.RopeFromCard[refCard­]];
refChar: REF CHAR => eventRope ¬ Rope.Cat[eventRope, " ", Convert.RopeFromChar[refChar­]];
refBool: REF BOOL => eventRope ¬ Rope.Cat[eventRope, " ", Convert.RopeFromBool[refBool­]];
l: LIST OF REF => {
eventRope ¬ Rope.Concat[eventRope, "("];
IF l # NIL THEN {
PrintRef[l.first];
FOR list: LIST OF REF ¬ l.rest, list.rest UNTIL list = NIL DO
PrintRef[list.first];
ENDLOOP;
};
eventRope ¬ Rope.Concat[eventRope, ")"];
};
ENDCASE => eventRope ¬ Rope.Concat[eventRope, " <?>"];
};
eventRope: Rope.ROPE ¬ "Button sends event:";
FOR list: LIST OF REF ANY ¬ events, list.rest UNTIL list = NIL DO
IF list.first = NIL THEN eventRope ¬ Rope.Concat[eventRope, " NIL"]
ELSE
PrintRef[list.first];
ENDLOOP;
MessageWindow.Append[message: eventRope, clearFirst: TRUE];
};
TypescriptHandler: EmbeddedButtons.RegisteredNotifyProc = {
PROC[events: LIST OF REF ANY, buttonInfo: ButtonInfo];
eventRope: Rope.ROPE ¬ "Button sends event:";
FOR list: LIST OF REF ANY ¬ events, list.rest UNTIL list = NIL DO
IF list.first = NIL THEN eventRope ¬ Rope.Concat[eventRope, " NIL"]
ELSE
WITH list.first SELECT FROM
atom: ATOM => eventRope ¬ Rope.Cat[eventRope, " ", Convert.RopeFromAtom[atom]];
rope: Rope.ROPE => eventRope ¬ Rope.Cat[eventRope, " ", Convert.RopeFromRope[rope]];
refInt: REF INT => eventRope ¬ Rope.Cat[eventRope, " ", Convert.RopeFromInt[refInt­]];
refCard: REF CARD => eventRope ¬ Rope.Cat[eventRope, " ", Convert.RopeFromCard[refCard­]];
refChar: REF CHAR => eventRope ¬ Rope.Cat[eventRope, " ", Convert.RopeFromChar[refChar­]];
refBool: REF BOOL => eventRope ¬ Rope.Cat[eventRope, " ", Convert.RopeFromBool[refBool­]];
ENDCASE => eventRope ¬ Rope.Concat[eventRope, " <?>"];
ENDLOOP;
SimpleFeedback.Append[routerName: $EmbeddedButtons, msgType: oneLiner, msgClass: $Typescript, msg: eventRope]
};
commandsDir: ROPE ~ "/Cedar/Commands/";
tempDir: ROPE ~ "/tmp/";
defaultSearchRules: LIST OF REF ¬ LIST[commandsDir];
defaultPrompt: ROPE ¬ "%l%% %l"; -- from CommandToolImpl
CommandToolHandler: EmbeddedButtons.RegisteredNotifyProc = {
PROC[events: LIST OF REF ANY, buttonInfo: ButtonInfo] RETURNS [result: REF];
events should be a list of ROPEs, each of which is a CommandLine.
cmdr: Commander.Handle ¬ NEW[Commander.CommandObject];
out: Rope.ROPE;
thisResult: REF;
inner: PROC = {
cmdr.in ¬ IO.noInputStream;
cmdr.out ¬ cmdr.err ¬ FeedbackOps.GetTypescriptStream[$SystemScript];
IF cmdr.out = NIL THEN cmdr.out ¬ cmdr.err ¬ IO.noWhereStream;
cmdr.propertyList ¬ LIST[
List.DotCons[key: $ErrorInputStream, val: IO.noInputStream],
List.DotCons[key: $Prompt, val: defaultPrompt],
List.DotCons[key: $WorkingDirectory, val: tempDir], -- needed?
List.DotCons[key: $SearchRules, val: CONS[FileNames.HomeDirectory[], defaultSearchRules]]];
cmdr.procData ¬ NIL;
FOR list: LIST OF REF ¬ events, list.rest UNTIL list = NIL DO
WITH list.first SELECT FROM
commandLine: Rope.ROPE => {
thisResult ¬ CommanderOps.DoCommand[commandLine, cmdr];
};
ENDCASE;
ENDLOOP;
IF thisResult = $Failure THEN result ¬ $Error ELSE result ¬ NIL;
};
ProcessProps.AddPropList[
List.PutAssoc[key: $WorkingDirectory, val: tempDir, aList: NIL],
inner];
We must have a WorkingDirectory property on the ProcessProps or CDs fail
};
ThisCommandToolHandler: EmbeddedButtons.RegisteredNotifyProc = {
PROC[events: LIST OF REF ANY, buttonInfo: ButtonInfo] RETURNS [result: REF];
events should be a list of ROPEs, each of which is a CommandLine.
buttonInfo is a button in a CommandTool. Send the commands to the CommandTool in which the button is embedded.
thisResult: REF;
cmdr: Commander.Handle;
WITH buttonInfo.doc.theDoc SELECT FROM
v: ViewerClasses.Viewer => {
What a kludge! Find the the Command.Handle from the STOP! menu button.
IF TypeScript.IsATypeScript[v] THEN {
menu: ViewerClasses.Menu ¬ v.menu;
menuEntry: ViewerClasses.MenuEntry ¬ Menus.FindEntry[menu, "STOP!"];
clientData: REF;
IF menuEntry = NIL THEN RETURN;
clientData ¬ Menus.SetClientData[menuEntry, NIL];
[] ¬ Menus.SetClientData[menuEntry, clientData];
WITH clientData SELECT FROM
cmd: Commander.Handle => cmdr ¬ cmd;
ENDCASE => RETURN;
}
ELSE RETURN;
};
ENDCASE => RETURN;
FOR list: LIST OF REF ¬ events, list.rest UNTIL list = NIL DO
WITH list.first SELECT FROM
commandLine: Rope.ROPE => {
commandLine ¬ Rope.Concat[commandLine, "\n"];
SendCommand[commandLine, cmdr];
};
ENDCASE;
ENDLOOP;
IF thisResult = $Failure THEN result ¬ $Error ELSE result ¬ NIL;
};
SendCommand: PROC [commandLine: ROPE, cmdr: Commander.Handle] = {
Copied from CommanderViewerImpl.ButtonImplButtonProc (which implements the buttons made by the CreateButton command).
viewer: ViewerClasses.Viewer;
viewer ¬ TiogaOps.GetSelection[primary].viewer;
WITH ViewerIO.GetViewerFromStream[cmdr.in] SELECT FROM
v: ViewerClasses.Viewer => {
bufferContents: REF TEXT ¬ ViewerIO.GetBuffer[cmdr.in];
IF bufferContents # NIL AND bufferContents.length > 0 AND bufferContents[bufferContents.length - 1] # '\n THEN {
FOR n: NAT DECREASING IN [0..bufferContents.length) DO
IF bufferContents[n] = '\n THEN {
EditedStream.UnAppendBufferChars[
stream: cmdr.in, nChars: bufferContents.length - n - 1];
EXIT;
}
REPEAT
FINISHED => EditedStream.UnAppendBufferChars[stream: cmdr.in, nChars: LAST[NAT]];
ENDLOOP;
};
IF viewer = v THEN {
If the selected viewer is the commandtool, then set the caret to the end, or the ViewerIO.TypeChars won't work.
ViewerTools.SetSelection[viewer: viewer, selection: NIL];
};
ViewerIO.TypeChars[editedViewerStream: cmdr.in, chars: commandLine];
};
ENDCASE => MessageWindow.Append["Bug in ButtonApplicationsImpl.SendCommand", TRUE]
};
RopeConcat: EBTypes.EBLanguageProc = {
PROC [arguments: LIST OF REF ANY, buttonInfo: ButtonInfo, clientData: REF] RETURNS [REF ANYNIL];
Take all of the arguments that are ROPEs and concatentate them.
rope: ROPE;
FOR list: LIST OF REF ¬ arguments, list.rest UNTIL list = NIL DO
WITH list.first SELECT FROM
r: ROPE => rope ¬ Rope.Concat[rope, r];
ENDCASE;
ENDLOOP;
RETURN[rope];
};
SelectionText: EBTypes.EBLanguageProc = {
PROC [arguments: LIST OF REF ANY, buttonInfo: ButtonInfo, clientData: REF] RETURNS [REF ANYNIL];
RETURN[ViewerTools.GetSelectionContents[]];
};
SelectionPropertyText: EBTypes.EBLanguageProc = {
PROC [arguments: LIST OF REF ANY, buttonInfo: ButtonInfo, clientData: REF] RETURNS [REF ANYNIL];
viewer: ViewerClasses.Viewer;
start: TiogaOps.Location;
key: ATOM;
IF arguments = NIL THEN RETURN[NIL];
WITH arguments.first SELECT FROM
a: ATOM => key ¬ a;
r: ROPE => key ¬ Atom.MakeAtom[r];
ENDCASE => RETURN[NIL];
[viewer, start] ¬ TiogaOps.GetSelection[primary];
IF viewer # NIL AND NOT viewer.destroyed AND NOT viewer.newFile THEN {
RETURN[TextEdit.GetCharProp[start.node, start.where, key]];
};
};
FileNameSelection: EBTypes.EBLanguageProc = {
PROC [arguments: LIST OF REF ANY, buttonInfo: ButtonInfo, clientData: REF] RETURNS [REF ANYNIL];
Replaced by the current selection if it appears to be a file name, otherwise replaced by the name of the selected viewer.
curSel: ROPE;
viewer: ViewerClasses.Viewer;
curSel ¬ ViewerTools.GetSelectionContents[];
curSel ¬ Rope.Substr[base: curSel, start: 0, len: curSel.Index[s2: "\n"]]; -- up to first CR
IF (Rope.SkipTo[s: curSel, pos: 0, skip: " \t"] = curSel.Length[]) AND (curSel.Length[] > 1) THEN RETURN[curSel];
viewer ¬ TiogaOps.GetSelection[primary].viewer;
IF viewer # NIL AND NOT viewer.destroyed AND NOT viewer.newFile THEN {
fileName: ROPE ¬ viewer.file;
fileName ¬ Rope.Substr[fileName, 0, Rope.SkipTo[fileName, 0, "!"]];
RETURN[fileName];
};
};
Buttonizers
MakeCommanderButtonData: PROC RETURNS [buttonDataRope: Rope.ROPE, commandRope, firstWord: Rope.ROPE] = {
commandRope ¬ ViewerTools.GetSelectionContents[];
firstWord ¬ IO.GetTokenRope[IO.RIS[commandRope]].token;
buttonDataRope ¬ Rope.Cat["Poppy1\n",
"Class: PopUpButton\n",
IO.PutFR["Menu: (\n (\"%g\" \"%g\" \"%g\")\n )\n", [rope[Convert.RopeFromRope[commandRope, FALSE]]], [rope[firstWord]], [rope[Convert.RopeFromRope[commandRope, FALSE]]] ],
"MessageHandler: CommandTool\n",
"Feedback: (\n (MouseMoved <SetCursor bullseye>)\n )"
];
};
ButtonDataFromSelection: PROC [handlerName: ROPE] RETURNS [buttonDataRope, commandRope: Rope.ROPE] = {
commandRope ¬ ViewerTools.GetSelectionContents[];
buttonDataRope ¬ Rope.Cat["Poppy1\n",
"Class: PopUpButton\n",
IO.PutFLR["Menu: (\n ((%g) \"Do %g Command\" \"Send %g: %g\")\n )\n", LIST[[rope[commandRope]], [rope[handlerName]], [rope[handlerName]], [rope[Convert.RopeFromRope[commandRope, FALSE]]]] ],
IO.PutFR1["MessageHandler: %g\n", [rope[handlerName]] ],
"Feedback: (\n (MouseMoved <SetCursor bullseye>)\n )"
];
};
Buttonize: EmbeddedButtons.RegisteredNotifyProc = {
PROC[events: LIST OF REF ANY, buttonInfo: ButtonInfo];
viewer: ViewerClasses.Viewer ¬ InputFocus.GetInputFocus[].owner;
buttonDataRope: Rope.ROPE;
rootOnly: BOOLIF events = NIL THEN FALSE ELSE events.first = $Root;
rootOnly: BOOL ¬ FALSE;
commandButtonizer: BOOL ¬ IF events = NIL THEN FALSE ELSE events.first = $Command;
fromString: BOOL ¬ IF events = NIL THEN FALSE ELSE events.first = $FromString;
IF fromString THEN {
WITH events.rest.first SELECT FROM
s: ROPE => {
buttonDataRope ¬ s;
Feedback.PutF[router, oneLiner, $Feedback, "Created button from string provided (%g ...)", [rope[Rope.Substr[buttonDataRope, 0, 30]]] ];
};
ENDCASE => {
Feedback.Append[router, oneLiner, $Feedback, "FromString buttonizer couldn't find a string."];
RETURN;
};
}
ELSE IF commandButtonizer THEN {
HandlerName: PROC [events: LIST OF REF] RETURNS [handlerName: ROPE] ~ {
IF events = NIL OR events.rest = NIL THEN RETURN["Commander"]
ELSE WITH events.rest.first SELECT FROM
r: ROPE => RETURN[r];
a: ATOM => RETURN[Atom.GetPName[a]];
ENDCASE => RETURN["MessageWindow"]; -- as a sort of warning indicator
};
handlerName: ROPE ¬ HandlerName[events];
IF Rope.Equal[handlerName, "Commander", FALSE] THEN {
commandRope, firstWord: Rope.ROPE;
[buttonDataRope, commandRope, firstWord] ¬ MakeCommanderButtonData[];
Feedback.PutFL[router, oneLiner, $Feedback, "Created Commander button (%g) (%g).", LIST[[rope[commandRope]], [rope[firstWord]]] ];
}
ELSE {
commandRope: Rope.ROPE;
[buttonDataRope, commandRope] ¬ ButtonDataFromSelection[handlerName];
Feedback.PutFL[router, oneLiner, $Feedback, "Created %g button (%g).", LIST[[rope[handlerName]], [rope[commandRope]]] ];
};
}
ELSE buttonDataRope ¬ EmbeddedButtons.GetRope[$ButtonDataLiteral, buttonInfo];
IF viewer.class.flavor = $Text OR viewer.class.flavor = $Typescript THEN {
postfixRope: Rope.ROPE ¬ EmbeddedButtons.GetRope[$PostfixLiteral, buttonInfo];
IF buttonDataRope # NIL THEN SetProp[viewer, $ButtonData, buttonDataRope, rootOnly];
IF postfixRope # NIL THEN SetProp[viewer, $Postfix, postfixRope, rootOnly];
}
ELSE IF viewer.class.flavor = $ActionArea AND buttonDataRope # NIL THEN {
GGSetProp[viewer, $ButtonData, buttonDataRope, rootOnly];
};
};
ButtonizeButtonizer: EmbeddedButtons.RegisteredNotifyProc = {
PROC[events: LIST OF REF ANY, buttonInfo: ButtonInfo] RETURNS [result: REF];
viewer: ViewerClasses.Viewer ¬ InputFocus.GetInputFocus[].owner;
buttonDataRope: Rope.ROPE;
rootOnly: BOOLIF events = NIL THEN FALSE ELSE events.first = $Root;
rootOnly: BOOL ¬ FALSE;
commanderButtonizer: BOOL ¬ IF events = NIL THEN FALSE ELSE events.first = $Command;
result ¬ Buttonize[events, buttonInfo];
IF commanderButtonizer THEN {
commandRope, firstWord: Rope.ROPE;
[buttonDataRope, commandRope, firstWord] ¬ MakeCommanderButtonData[];
Feedback.PutFL[router, oneLiner, $Feedback, "Created command buttonizer (%g) (%g)", LIST[[rope[commandRope]], [rope[firstWord]]] ];
}
ELSE {
Feedback.Append[router, oneLiner, $Feedback, "Creating buttonizer from ButtonDataLiteral"];
buttonDataRope ¬ EmbeddedButtons.GetRope[$ButtonDataLiteral, buttonInfo];
};
IF viewer.class.flavor = $Text OR viewer.class.flavor = $Typescript THEN {
postfixRope: Rope.ROPE ¬ EmbeddedButtons.GetRope[$PostfixLiteral, buttonInfo];
IF buttonDataRope # NIL THEN SetProp[viewer, $ButtonDataLiteral, buttonDataRope, rootOnly];
IF postfixRope # NIL THEN SetProp[viewer, $PostfixLiteral, postfixRope, rootOnly];
}
ELSE IF viewer.class.flavor = $ActionArea AND buttonDataRope # NIL THEN {
GGSetProp[viewer, $ButtonDataLiteral, buttonDataRope, rootOnly];
};
};
UnButtonize: EmbeddedButtons.RegisteredNotifyProc = {
PROC[events: LIST OF REF ANY, buttonInfo: ButtonInfo]
viewer: ViewerClasses.Viewer ¬ InputFocus.GetInputFocus[].owner;
rootOnly: BOOL ¬ IF events = NIL THEN FALSE ELSE events.first = $Root;
IF viewer.class.flavor = $Text OR viewer.class.flavor = $Typescript THEN {
RemProp[viewer, $ButtonData, rootOnly];
RemProp[viewer, $ButtonFeedback, rootOnly];
RemProp[viewer, $ButtonTarget, rootOnly];
RemProp[viewer, $Postfix, rootOnly];
}
ELSE IF viewer.class.flavor = $ActionArea THEN {
GGRemProp[viewer, $ButtonData, rootOnly];
GGRemProp[viewer, $ButtonFeedback, rootOnly];
GGRemProp[viewer, $ButtonTarget, rootOnly];
};
};
SetProp: PROC [viewer: Viewer, key: ATOM, valueRope: Rope.ROPE, rootOnly: BOOL] = {
Put: PROC [node: TextNode.Ref, start, size: INT] = {
value: REF ~ NodeProps.DoSpecs[key, valueRope];
TextEdit.PutCharProp[node: node, index: start, name: key, value: value, nChars: size, event: TEditInput.CurrentEvent[], root: root]
};
pSel: TEditDocument.Selection;
root: TextNode.Ref;
TEditSelection.LockSel[primary, "ButtonizerImpl.SetProp"];
pSel ¬ TEditOps.GetSelData[];
IF NOT TEditInputOps.CheckReadonly[pSel] THEN {
TEditSelection.UnlockSel[primary];
RETURN;
};
root ¬ TEditSelection.SelectionRoot[pSel];
[] ¬ TEditLocks.Lock[root, "ButtonizerImpl.SetProp"];
ForEachNode[pSel, Put !
RuntimeError.UNCAUGHT => {
MessageWindow.Append["Uncaught error in ButtonizerImpl.SetProp", TRUE];
MessageWindow.Blink[];
CONTINUE;
};
];
TEditSelection.UnlockDocAndPSel[root];
};
RemProp: PROC [viewer: Viewer, key: ATOM, rootOnly: BOOL] = {
Rem: PROC [node: TextNode.Ref, start, size: INT] = {
TextEdit.PutCharProp[node: node, index: start, name: key, value: NIL, nChars: size, event: TEditInput.CurrentEvent[], root: root]
};
pSel: TEditDocument.Selection;
root: TextNode.Ref;
TEditSelection.LockSel[primary, "ButtonizerImpl.RemProp"];
pSel ¬ TEditOps.GetSelData[];
IF NOT TEditInputOps.CheckReadonly[pSel] THEN {
TEditSelection.UnlockSel[primary];
RETURN;
};
root ¬ TEditSelection.SelectionRoot[pSel];
[] ¬ TEditLocks.Lock[root, "ButtonizerImpl.RemProp"];
ForEachNode[pSel, Rem !
RuntimeError.UNCAUGHT => {
MessageWindow.Append["Uncaught error in ButtonizerImpl.RemProp", TRUE];
MessageWindow.Blink[];
CONTINUE;
};
];
TEditSelection.UnlockDocAndPSel[root];
};
GGSetProp: PROC [viewer: Viewer, key: ATOM, valueRope: Rope.ROPE, rootOnly: BOOL] = {
IF rootOnly THEN GGUserInput.InputNotify[viewer, LIST[$SetRootProp, Rope.Cat[Atom.GetPName[key], " ", valueRope]]]
ELSE GGUserInput.InputNotify[viewer, LIST[$SetProp, Rope.Cat[Atom.GetPName[key], " ", valueRope]]];
};
GGSetProp: PROC [viewer: Viewer, key: ATOM, valueRope: Rope.ROPE, rootOnly: BOOL] = {
propClass: PropRegistry.RegistryClass;
setProp: PropRegistry.PropSetProc;
propClass ¬ PropRegistry.GetRegistered[$ActionArea];
IF propClass = NIL THEN RETURN;
setProp ¬ propClass.setProp;
IF setProp # NIL THEN setProp[key: key, doc: viewer, hint: NIL, prop: valueRope, edited: TRUE];
};
GGRemProp: PROC [viewer: Viewer, key: ATOM, rootOnly: BOOL] = {
IF rootOnly THEN GGUserInput.InputNotify[viewer, LIST[$RemoveRootProp, Atom.GetPName[key]]]
ELSE GGUserInput.InputNotify[viewer, LIST[$RemoveProp, Atom.GetPName[key]]];
};
GGRemProp: PROC [viewer: Viewer, key: ATOM, rootOnly: BOOL] = {
propClass: PropRegistry.RegistryClass;
remProp: PropRegistry.PropRemProc;
propClass ¬ PropRegistry.GetRegistered[$ActionArea];
IF propClass = NIL THEN RETURN;
remProp ¬ propClass.remProp;
IF remProp # NIL THEN remProp[key: key, doc: viewer, hint: NIL, edited: TRUE];
};
ForEachNode: PROC [pSel: TEditDocument.Selection,
proc: PROC [node: TextNode.Ref, start: INT, size: INT]] = {
FOR node: TextNode.Ref ¬ pSel.start.pos.node, TextNode.StepForward[node] DO
start: INT ¬ 0;
end: INT ¬ TextEdit.Size[node];
IF node = pSel.start.pos.node AND pSel.start.pos.where # TextNode.NodeItself THEN {
start ¬ pSel.start.pos.where;
};
IF node = pSel.end.pos.node AND pSel.end.pos.where # TextNode.NodeItself THEN {
end ¬ MIN[end, pSel.end.pos.where+1];
};
proc[node: node, start: start, size: end-start];
IF node = pSel.end.pos.node THEN EXIT;
ENDLOOP;
};
Initialization
router: FeedbackTypes.MsgRouter ¬ Feedback.EnsureRouter[$EmbeddedButtons];
FeedbackOps.SetMultiTypescript[router, $SystemScript, LIST[$SyntaxError, $InternalError, $Typescript, $UserError, $Feedback]];
FeedbackOps.SetMultiMessageWindow[router, TRUE, LIST[$UserError]];
FeedbackOps.SetMultiMessageWindow[router, FALSE, LIST[$Screen, $Feedback]];
EmbeddedButtons.RegisterApplication[$Tioga, TiogaHandler];
EmbeddedButtons.RegisterApplication[$MessageWindow, MessageWindowHandler];
EmbeddedButtons.RegisterApplication[$Typescript, TypescriptHandler];
EmbeddedButtons.RegisterApplication[$CommandTool, CommandToolHandler];
EmbeddedButtons.RegisterApplication[$ThisCommandTool, ThisCommandToolHandler];
EmbeddedButtons.RegisterApplication[$Buttonizer, Buttonize];
EmbeddedButtons.RegisterApplication[$ButtonizerButtonizer, ButtonizeButtonizer];
EmbeddedButtons.RegisterApplication[$UnButtonizer, UnButtonize];
EmbeddedButtons.RegisterPoppyProc[$Concat, RopeConcat];
EmbeddedButtons.RegisterPoppyProc[$SelectionText, SelectionText];
EmbeddedButtons.RegisterPoppyProc[$SelectionPropertyText, SelectionPropertyText];
CreateButton look-alike commands
EmbeddedButtons.RegisterPoppyProc[$CurrentSelection, SelectionText];
EmbeddedButtons.RegisterPoppyProc[$FileNameSelection, FileNameSelection];
END.