WalnutMsgSetButtonsImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Willie-Sue, September 18, 1985 10:04:07 am PDT
Pavel, February 7, 1986 11:43:05 am PST
Contents: co-ordinates MsgSet button handling for WalnutControlWindow
created October, 1982 by Willie-Sue
Last edit by:
Willie-Sue on: January 3, 1985 4:49:23 pm PST
Donahue on: January 31, 1985 3:13:33 pm PST
(To be consistent with new WalnutDisplayerOps, WalnutDisplayerOpsInternal)
(Restart code calls proc to redisplay all message set viewers, since check for version is done there)
(Again, this got much smaller and simpler through changes to WalnutWindow, WalnutWindowInternal)
DIRECTORY
Containers USING [ChildXBound],
Rope USING [ROPE, Cat, Compare, Equal, Length],
TBQueue USING [AppendToTiogaButton],
TiogaButtons
USING [ CreateButton,
TiogaButtonProc, TiogaButton,
AppendToButton, ChangeButtonLooks, CreateViewer, DeleteButton],
TiogaOps USING [InsertRope],
UserProfile USING [Number, Token],
VFonts USING [StringWidth],
ViewerOps
USING [ComputeColumn, DestroyViewer, GrowViewer, MoveViewer,
OpenIcon, PaintViewer, SetOpenHeight],
ViewerClasses USING [Viewer],
ViewerSpecs USING [openLeftWidth, openRightWidth, scrollBarW],
WalnutOps,
WalnutDisplayerInternal USING [QDisplayMsgSet, displayMsgSetInIcon],
WalnutWindow USING [],
WalnutWindowInternal
USING[walnut, walnutTS, walnutRulerBefore, walnutRulerAfter, MsgSetButton, MsgSetButtonObject, walnutQueue,
walnutIcon, newMailIcon,
labelledWalnutIcon, labelledNewMailIcon,
unLabelledWalnutIcon, unLabelledNewMailIcon];
WalnutMsgSetButtonsImpl:
CEDAR
PROGRAM
IMPORTS
Rope, UserProfile,
Containers, TBQueue, TiogaButtons, TiogaOps, VFonts, ViewerOps, ViewerSpecs,
WalnutOps, WalnutDisplayerInternal, WalnutWindowInternal
EXPORTS WalnutWindow, WalnutWindowInternal =
BEGIN OPEN WalnutDisplayerInternal, WalnutWindowInternal;
ROPE: TYPE = Rope.ROPE;
Viewer: TYPE = ViewerClasses.Viewer;
TiogaButton: TYPE = TiogaButtons.TiogaButton;
MsgSet: TYPE = WalnutOps.MsgSet;
msgSetsVersion: PUBLIC INT ← -1;
msgSetsTViewer: PUBLIC Viewer ← NIL;
msbDefaultLooks:
PUBLIC
ROPE ←
UserProfile.Token[key: "Walnut.MsgSetButtonDefaultLooks", default: ""];
msbSelectedLooks:
PUBLIC ROPE ←
UserProfile.Token[key: "Walnut.MsgSetButtonSelectedLooks", default: "bi"];
lineHeight: INT ← 12;
maxLines: INT ← 10;
spaceWidth: INT ← VFonts.StringWidth["P"];
selectedMsgSetButtons: PUBLIC MsgSetButton ← NIL; -- List of selected MsgSets (may be empty)
firstMsgSetButton: PUBLIC MsgSetButton ← NIL; -- head of List of MsgSets (never empty
deletedMsgSetButton: PUBLIC MsgSetButton ← NIL; -- The message set button for Deleted
activeMsgSetButton: PUBLIC MsgSetButton ← NIL; -- The message set button for Active
Invariant:
IF displayMsgSetInIcon AND selectedMsgSetButtons # NIL THEN
Current icon is labelled and the label = selectedMsgSetButtons.msgSet.name
ELSE
Current icon is unlabelled
The invariant is established at the beginning by initialising as follows:
walnutIcon ← unLabelledWalnutIcon
newMailIcon ← unLabelledNewMailIcon
walnut.icon ← walnutIcon
selectedMsgSetButtons ← NIL
The maintenance of the invariant is split between this procedure and DeselectMsgSet, below.
SelectMsgSetProc: TiogaButtons.TiogaButtonProc = {
IF red THEN deselect all & select this one; IF yellow then display;
IF blue THEN toggle whether selected or not
button: TiogaButtons.TiogaButton ← NARROW[parent];
msbH: MsgSetButton = NARROW[clientData];
msb, msb2: MsgSetButton;
IF (mouseButton = red)
AND shift
THEN {
TiogaOps.InsertRope[msbH.msgSet.name];
RETURN;
};
IF mouseButton = yellow
THEN {
MSDisplay[msbH, shift];
RETURN;
};
IF mouseButton = red
THEN {
-- deselect any selected
IF (msb ← selectedMsgSetButtons) #
NIL
THEN {
selectedMsgSetButtons ← NIL;
DO
TiogaButtons.ChangeButtonLooks[
button: msb.button,
addLooks: msbDefaultLooks,
removeLooks: msbSelectedLooks
];
IF (msb2 ← msb.selected) =
NIL
THEN
EXIT;
msb.selected ← NIL;
msb ← msb2;
ENDLOOP;
}
}
ELSE {
-- blue button, toggle the state of this msgSet
FOR msb ← selectedMsgSetButtons, msb.selected
UNTIL msb=
NIL
DO
IF msb = msbH
THEN {
-- This one was already selected; deselect it and quit
DeselectMsgSet[msbH];
RETURN;
};
ENDLOOP;
msbH.selected ← selectedMsgSetButtons;
};
Here we actually select the given button
selectedMsgSetButtons ← msbH;
TiogaButtons.ChangeButtonLooks[
button: button,
addLooks: msbSelectedLooks,
removeLooks: msbDefaultLooks
];
Fix up the icon, if necessary
FixIconAndLabel[];
};
FixIconAndLabel:
PROC = {
-- This procedure does not repaint the icon, since most callers won't want that
IF displayMsgSetInIcon
THEN {
IF selectedMsgSetButtons =
NIL
THEN {
walnut.label ← NIL;
walnutIcon ← unLabelledWalnutIcon;
newMailIcon ← unLabelledNewMailIcon;
}
ELSE {
label : ROPE ← selectedMsgSetButtons.msgSet.name;
FOR msb: MsgSetButton ← selectedMsgSetButtons.selected, msb.selected
UNTIL msb =
NIL
DO
label ← Rope.Cat[label, ", ", msb.msgSet.name];
ENDLOOP;
walnut.label ← label;
walnutIcon ← labelledWalnutIcon;
newMailIcon ← labelledNewMailIcon;
};
IF walnut.icon = labelledWalnutIcon
OR walnut.icon = unLabelledWalnutIcon
THEN
walnut.icon ← walnutIcon
ELSE
walnut.icon ← newMailIcon;
};
};
ShowMsgSetButtons:
PUBLIC
PROC = {
msL: LIST OF ROPE;
bt: TiogaButtons.TiogaButton;
msb: MsgSetButton;
first: BOOL ← TRUE;
ms: ROPE;
visibleSpace: INT;
version, numMsgSets: INT;
[version, numMsgSets] ← WalnutOps.MsgSetsInfo[];
IF firstMsgSetButton #
NIL
THEN
IF version = msgSetsVersion
THEN {
-- check for changed, displayed msgSets
FOR msb: MsgSetButton ← firstMsgSetButton, msb.next
UNTIL msb=
NIL
DO
IF msb.msViewer #
NIL
THEN {
IF msb.msViewer.destroyed
THEN {
msb.msViewer ← NIL;
msb.msgSet.version ← -1;
}
ELSE [] ← WalnutDisplayerInternal.QDisplayMsgSet[msb: msb]
}
ELSE msb.msgSet.version ← -1; -- might have been displayed once
ENDLOOP;
RETURN;
};
[msL, msgSetsVersion] ← WalnutOps.MsgSetNames[alphaOrder: TRUE];
calculate how big the area for msgSet buttons should be
BEGIN
numLines: INT ← UserProfile.Number["Walnut.NumMsgSetButtonsLines", -1];
IF numLines = -1
THEN {
colWidth:
INT ← (
IF walnut.column = right
THEN ViewerSpecs.openRightWidth
ELSE ViewerSpecs.openLeftWidth) - ViewerSpecs.scrollBarW;
numChars, totalCharWidth: INT ← 0;
FOR nL:
LIST
OF
ROPE ← msL, nL.rest
UNTIL nL=
NIL
DO
numChars ← numChars + nL.first.Length[] + 2; -- two spaces between
ENDLOOP;
totalCharWidth ← numChars*spaceWidth;
numLines ← (totalCharWidth/colWidth) + 1;
IF numLines <= 0
THEN numLines ← 1
ELSE IF numLines > maxLines THEN numLines ← maxLines;
};
visibleSpace ← numLines * lineHeight + 1;
END;
IF msgSetsTViewer # NIL THEN DestroyAllMsgSetButtons[]; -- start from scratch; it's easier
msgSetsTViewer ← TiogaButtons.CreateViewer[
info: [wy: walnutRulerBefore.wy + 2, ww: walnut.ww,
wh: visibleSpace, parent: walnut, border: FALSE] ];
Containers.ChildXBound[walnut, msgSetsTViewer];
IF walnutRulerAfter.wy # walnutRulerBefore.wy + visibleSpace
THEN {
ViewerOps.MoveViewer[walnutRulerAfter, walnutRulerAfter.wx,
walnutRulerBefore.wy+walnutRulerBefore.wh+visibleSpace,
walnutRulerAfter.ww, walnutRulerAfter.wh, FALSE];
ViewerOps.MoveViewer[walnutTS, walnutTS.wx,
walnutRulerAfter.wy+walnutRulerAfter.wh+1, walnutTS.ww,
walnutTS.wh, FALSE];
ViewerOps.SetOpenHeight[msgSetsTViewer, visibleSpace];
ViewerOps.ComputeColumn[walnut.column];
};
msb← firstMsgSetButton ←
NEW[MsgSetButtonObject ← [ msgSet: WalnutOps.MsgSet[name: " "]]];
bt ← TiogaButtons.CreateButton[
viewer: msgSetsTViewer, rope: " ", clientData: firstMsgSetButton];
firstMsgSetButton.button ← bt;
msb ← activeMsgSetButton ← AddMSButton[msb, WalnutOps.ActiveMsgSetName, FALSE];
msb ← deletedMsgSetButton← AddMSButton[msb, WalnutOps.DeletedMsgSetName];
FOR msL2:
LIST
OF
ROPE ← msL, msL2.rest
UNTIL msL2 =
NIL
DO
IF ~Rope.Equal[(ms ← msL2.first), WalnutOps.ActiveMsgSetName,
FALSE]
AND
~Rope.Equal[ms, WalnutOps.DeletedMsgSetName,
FALSE]
THEN
msb ← AddMSButton[msb, ms];
ENDLOOP;
};
GetSelectedMsgSets:
PUBLIC
PROC
RETURNS[msL:
LIST
OF MsgSetButton] = {
FOR msB: MsgSetButton ← selectedMsgSetButtons, msB.selected
UNTIL msB=
NIL
DO
msL ← CONS[msB, msL];
ENDLOOP;
};
AddMsgSetButton:
PUBLIC
PROC[msgSet: Rope.
ROPE, select:
BOOL] = {
thisMsb: MsgSetButton;
prevMsb: MsgSetButton ← deletedMsgSetButton;
DO
nextMsb: MsgSetButton ← prevMsb.next;
IF nextMsb =
NIL
THEN
{ thisMsb ← AddMSButton[prevMsb, msgSet]; EXIT};
IF Rope.Compare[msgSet, nextMsb.msgSet.name] = less
THEN
{thisMsb ← AddMSButton[prevMsb, msgSet]; EXIT};
prevMsb ← nextMsb;
ENDLOOP;
IF select
THEN SelectMsgSetProc[
-- red-select new MsgSet
parent: thisMsb.button, clientData: thisMsb];
};
DeleteMsgSetButton:
PUBLIC
PROC[msgSet:
ROPE] = {
if msgSet is Active, just destroy viewer, but not button
prevMsb: MsgSetButton ← firstMsgSetButton;
FOR msb: MsgSetButton ← firstMsgSetButton, msb.next UNTIL msb = NIL DO
IF Rope.Equal[msb.msgSet.name, msgSet,
FALSE]
THEN
{ msV: Viewer ← msb.msViewer;
IF msV # NIL AND ~msV.destroyed THEN ViewerOps.DestroyViewer[msV];
IF Rope.Equal[msgSet,WalnutOps.ActiveMsgSetName]
THEN
{ msb.msViewer ← NIL; RETURN};
DeselectMsgSet[msb];
prevMsb.next ← msb.next;
TiogaButtons.DeleteButton[msb.spaceButton];
TiogaButtons.DeleteButton[msb.button];
RETURN
};
prevMsb ← msb;
ENDLOOP;
};
DestroyAllMsgSetButtons:
PUBLIC
PROC = {
selectedMsgSetButtons ← NIL;
FOR msb: MsgSetButton ← firstMsgSetButton, msb.next
UNTIL msb=
NIL
DO
IF msb.msViewer # NIL THEN ViewerOps.DestroyViewer[msb.msViewer];
msb.msViewer ← NIL;
ENDLOOP;
firstMsgSetButton ← NIL;
ViewerOps.MoveViewer[walnutRulerAfter, walnutRulerAfter.wx,
walnutRulerBefore.wy+walnutRulerBefore.wh+14+2, walnutRulerAfter.ww,
walnutRulerAfter.wh, FALSE];
ViewerOps.MoveViewer[walnutTS, walnutTS.wx,
walnutRulerAfter.wy+walnutRulerAfter.wh+1, walnutTS.ww,
walnutTS.wh, FALSE];
ViewerOps.DestroyViewer[msgSetsTViewer, FALSE];
msgSetsTViewer ← NIL;
ViewerOps.ComputeColumn[walnut.column];
ViewerOps.PaintViewer[walnut, client];
};
SelectMsgSetsFromMSNames:
PUBLIC
PROC [msNames:
LIST
OF
ROPE]
RETURNS[notFound: LIST OF ROPE] = {
-- Selects the message set buttons in the Walnut Control viewer which corresponds to the list of msNames given.
first: BOOLEAN ← TRUE;
IF walnut = NIL THEN RETURN[msNames];
FOR msNameList:
LIST
OF
ROPE ← msNames, msNameList.rest
UNTIL msNameList =
NIL
DO
msb: MsgSetButton ← GetButton[msNameList.first];
IF msb =
NIL
THEN {
notFound ← CONS[msNameList.first, notFound];
LOOP
};
SelectMsgSetProc[
parent: msb.button,
mouseButton: IF first THEN red ELSE blue,
clientData: msb];
first ← FALSE;
ENDLOOP;
IF displayMsgSetInIcon
AND walnut.iconic
THEN
ViewerOps.PaintViewer[walnut, all];
};
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
AddMSButton:
PROC[prevMsb: MsgSetButton, msgSet:
ROPE, needsSpace:
BOOL ←
TRUE]
RETURNS[msbH: MsgSetButton] = {
assumes msgSet does not already have a button; adds it after prevMsb
spaceBt, newBt: TiogaButtons.TiogaButton;
IF needsSpace
THEN
spaceBt ← TiogaButtons.AppendToButton[button: prevMsb.button, rope: " "]
ELSE spaceBt ← prevMsb.button;
msbH ← NEW[MsgSetButtonObject ← [msgSet: [name: msgSet], next: prevMsb.next] ];
newBt ← TBQueue.AppendToTiogaButton[
q: walnutQueue, button: spaceBt, rope: msgSet,
looks: msbDefaultLooks, proc: SelectMsgSetProc, clientData: msbH];
msbH.spaceButton ← spaceBt;
msbH.button ← newBt;
prevMsb.next ← msbH;
};
DeselectMsgSet:
PROC[msbH: MsgSetButton] = {
msb: MsgSetButton ← selectedMsgSetButtons;
FOR msb2: MsgSetButton ← msb, msb2.selected
UNTIL msb2=
NIL
DO
IF msb2 = msbH
THEN {
-- found on list so take off
msb.selected ← msb2.selected;
IF msbH = selectedMsgSetButtons
THEN
selectedMsgSetButtons ← msbH.selected;
msbH.selected ← NIL;
TiogaButtons.ChangeButtonLooks[
button: msbH.button,
addLooks: msbDefaultLooks,
removeLooks: msbSelectedLooks
];
Fix up the icon, if necessary
FixIconAndLabel[];
RETURN
};
msb ← msb2;
ENDLOOP;
};
MSDisplay:
PROC[msb: MsgSetButton, shift:
BOOL] = {
msV: Viewer = msb.msViewer;
IF (msV #
NIL)
AND ~msV.destroyed
THEN
{
IF msV.iconic
THEN ViewerOps.OpenIcon[msV, shift]
ELSE
IF shift
THEN ViewerOps.GrowViewer[msV]
ELSE ViewerOps.PaintViewer[msV, all] }
ELSE [] ← WalnutDisplayerInternal.QDisplayMsgSet[msb, msV, shift];
};
GetButton:
PUBLIC
PROC[msgSet:
ROPE]
RETURNS[MsgSetButton] = {
FOR msb: MsgSetButton ← firstMsgSetButton, msb.next UNTIL msb = NIL DO
IF Rope.Equal[msb.msgSet.name, msgSet]
THEN
RETURN[msb];
ENDLOOP;
RETURN[NIL];
};
END.