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 ANY ← NIL];
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 ANY ← NIL];
RETURN[ViewerTools.GetSelectionContents[]];
};
SelectionPropertyText: EBTypes.EBLanguageProc = {
PROC [arguments: LIST OF REF ANY, buttonInfo: ButtonInfo, clientData: REF] RETURNS [REF ANY ← NIL];
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 ANY ← NIL];
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: BOOL ← IF 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: BOOL ← IF 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.