File: WalnutMsgSetButtonsImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Contents: co-ordinates MsgSet button handling for WalnutControlWindow
Willie-Sue, March 20, 1985 9:08:04 am PST
created October, 1982 by Willie-Sue
Last edit by:
Willie-Sue on: September 19, 1984 2:49:40 pm PDT
DIRECTORY
Buttons USING [ButtonProc, SetDisplayStyle],
Rope,
VFonts USING [StringWidth],
ViewerOps USING [AddProp, DestroyViewer, FetchProp, GrowViewer, MoveViewer,
OpenIcon, PaintViewer],
ViewerClasses USING [Viewer],
ViewerSpecs USING[openLeftWidth, openRightWidth],
WalnutDB USING [Entity, Msg, MsgSet, activeMsgSet, deletedMsgSet, MsgSetDomain,
DeclareMsgSet, EqEntities, GetEntitiesInDomain, GetName],
WalnutMsgOps USING [BuildMsgSetDisplayer, MsgSetInViewer],
WalnutViewer USING [AnotherButton],
WalnutWindow USING [MsgSetButton, MsgSetButtonObject,
msgSetBorders, walnut, walnutQueue, walnutRulerBefore, walnutRulerAfter,
walnutTS];
WalnutMsgSetButtonsImpl: CEDAR PROGRAM
IMPORTS
Buttons,
VFonts, ViewerOps, ViewerSpecs,
WalnutDB, WalnutMsgOps, WalnutViewer, WalnutWindow
EXPORTS WalnutWindow =
BEGIN OPEN WalnutDB, WalnutWindow;
--------------------------
ROPE: TYPE = Rope.ROPE;
Viewer: TYPE = ViewerClasses.Viewer;
MsgSetButtonNotFound: SIGNAL = CODE;  -- something is wrong
selectedMsgSetButtons: PUBLIC MsgSetButton← NIL; -- List of selected MsgSets (may be empty)
lastMsgSetButton: PUBLIC MsgSetButton← NIL;   -- tail of List of MsgSets (never empty)
firstMsgSetButton: PUBLIC MsgSetButton← NIL;   -- head of List of MsgSets (never empty
SelectMsgSetProc: Buttons.ButtonProc =
IF red THEN deselect all & select this one; IF yellow then display;
IF blue THEN toggle whether selected or not
BEGIN
viewer: Viewer← NARROW[parent];
msbH: MsgSetButton← NARROW[ViewerOps.FetchProp[viewer, $msbH]];
msb, msb2: MsgSetButton;
IF mouseButton = yellow THEN {MSDisplay[msbH, shift]; RETURN};
IF mouseButton = red THEN  -- deselect any selected
{ IF (msb← selectedMsgSetButtons) # NIL THEN
{ selectedMsgSetButtons← NIL;
DO
Buttons.SetDisplayStyle[msb.selector, $BlackOnWhite];
IF (msb2← msb.selected) = NIL THEN EXIT;
msb.selected← NIL;
msb← msb2;
ENDLOOP;
}
}
ELSE -- blue button
{ FOR msb← selectedMsgSetButtons, msb.selected UNTIL msb=NIL DO
IF msb = msbH THEN {DeselectMsgSet[msbH]; RETURN};
ENDLOOP; 
msbH.selected ← selectedMsgSetButtons;
};
selectedMsgSetButtons← msbH;
Buttons.SetDisplayStyle[viewer, $WhiteOnBlack];
END;
--------------------------
ShowMsgSetButtons: PUBLIC PROC =
BEGIN
eL: LIST OF Entity← GetEntitiesInDomain[d: MsgSetDomain, alphaOrder: TRUE];
ms: Entity;
v: Viewer;
IF firstMsgSetButton # NIL THEN { UpdateMSBs[eL]; RETURN};
v← WalnutViewer.AnotherButton[q: walnutQueue, name: "Active", proc: SelectMsgSetProc,
sib: walnutRulerBefore, border: msgSetBorders, newLine: TRUE, paint: FALSE];
firstMsgSetButton← lastMsgSetButton←
NEW[MsgSetButtonObject← [msgSet: activeMsgSet, selector: v]];
ViewerOps.AddProp[v, $msbH, lastMsgSetButton];
AddMSButton[deletedMsgSet, "Deleted", FALSE];
FOR elT: LIST OF Entity← eL, elT.rest UNTIL elT=NIL DO
ms← elT.first;
IF ~EqEntities[ms, deletedMsgSet] AND ~EqEntities[ms, activeMsgSet] THEN
AddMSButton[ms, GetName[ms], FALSE]; -- changes lastMsgSetButton
ENDLOOP;
END;
GetSelectedMsgSets: PUBLIC PROC RETURNS[msL: LIST OF MsgSetButton] =
BEGIN
FOR msB: MsgSetButton← selectedMsgSetButtons, msB.selected UNTIL msB=NIL DO
msL← CONS[msB, msL];
ENDLOOP;
END;
AddMsgSetButton: PUBLIC PROC[msgSet: MsgSet, msName: ROPE, select: BOOL] =
BEGIN
AddMSButton[msgSet, msName];
IF select THEN SelectMsgSetProc[lastMsgSetButton.selector]; -- red-select new MsgSet
END;
DeleteMsgSetButton: PUBLIC PROC[msgSet: MsgSet] =
if msgSet is Active, just destroy viewer, but not button
BEGIN
prevMsb: MsgSetButton← firstMsgSetButton;
FOR msb: MsgSetButton← firstMsgSetButton, msb.next UNTIL msb = NIL DO
IF EqEntities[msb.msgSet, msgSet] THEN
{ msV: Viewer← msb.msViewer;
IF msV # NIL AND ~msV.destroyed THEN ViewerOps.DestroyViewer[msV];
IF EqEntities[msgSet, activeMsgSet] THEN { msb.msViewer← NIL; RETURN};
DeselectMsgSet[msb];
IF msb = lastMsgSetButton THEN lastMsgSetButton← prevMsb;
prevMsb.next← msb.next;
ViewerOps.DestroyViewer[msb.selector];
RETURN
};
prevMsb← msb;
ENDLOOP;
END;
FindMSViewer: PUBLIC PROC[msgSet: MsgSet] RETURNS[Viewer] =
BEGIN
FOR msb: MsgSetButton← firstMsgSetButton, msb.next UNTIL msb = NIL DO
IF EqEntities[msb.msgSet, msgSet] THEN
{IF msb.msViewer = NIL THEN RETURN[NIL]
ELSE IF ~msb.msViewer.destroyed THEN RETURN[msb.msViewer] ELSE
{ msb.msViewer← NIL; RETURN[NIL]}};
ENDLOOP;
SIGNAL MsgSetButtonNotFound;
RETURN[NIL];
END;
DisplayMsgSet: PUBLIC PROC[msgSet: MsgSet] RETURNS[Viewer] =
{ msb: MsgSetButton;
MSDisplay[msb← FindMSBForMsgSet[msgSet], FALSE];
RETURN[msb.msViewer];
};
DestroyAllMsgSetButtons: PUBLIC PROC =
BEGIN
selectedMsgSetButtons← NIL;
FOR msb: MsgSetButton← firstMsgSetButton, msb.next UNTIL msb=NIL DO
ViewerOps.DestroyViewer[msb.selector, FALSE];
ENDLOOP;
firstMsgSetButton← lastMsgSetButton← 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.PaintViewer[walnut, client];
END;
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
AddMSButton: PROC[msgSet: MsgSet, msName: ROPE, paint: BOOLTRUE] =
assumes msgSet does not already have a button; there is always a lastMsgSetButton
BEGIN
msbH: MsgSetButton;
newV: Viewer;
v: Viewer← lastMsgSetButton.selector;
x: INTEGER← v.wx + v.ww + 2;  -- x for new button
width: INT← VFonts.StringWidth[msName];
parentWidth: INTEGERIF ~walnut.iconic THEN walnut.cw
ELSE IF walnut.column = left THEN ViewerSpecs.openLeftWidth
ELSE ViewerSpecs.openRightWidth;
newLine: BOOL← (x + width + 3) >= parentWidth;  -- will button fit on this line??
IF newLine AND (walnutTS#NIL) THEN   -- move Rule & typescript viewers
{ nH: INTEGER← v.wh + (IF msgSetBorders THEN 1 ELSE 0);
ViewerOps.MoveViewer[walnutTS, walnutTS.wx, walnutTS.wy+nH, walnutTS.ww,
walnutTS.wh, FALSE];
ViewerOps.MoveViewer[walnutRulerAfter, walnutRulerAfter.wx,
walnutRulerAfter.wy + nH,
walnutRulerAfter.ww,
walnutRulerAfter.wh, FALSE];
IF paint THEN ViewerOps.PaintViewer[walnut, client];
};
newV← WalnutViewer.AnotherButton[q: walnutQueue, name: msName,
proc: SelectMsgSetProc,
sib: v, border: msgSetBorders, newLine: newLine, paint: paint];
msbH← NEW[MsgSetButtonObject← [msgSet: msgSet, selector: newV]];
ViewerOps.AddProp[newV, $msbH, msbH];
lastMsgSetButton.next← msbH;
lastMsgSetButton← msbH;
END;
UpdateMSBs: PROC[eL: LIST OF Entity] =
BEGIN
ms, ms2: Entity;
newMS, lastNewMS: LIST OF MsgSet;
elT: LIST OF Entity← eL;
prevMsb: MsgSetButton;
msb: MsgSetButton← firstMsgSetButton;
DeleteMSB: PROC[msButton: MsgSetButton] =
BEGIN
DeselectMsgSet[msButton];
ViewerOps.DestroyViewer[msb.selector];
END;
msb.msgSet← DeclareMsgSet[msb.selector.name].msgSet;  -- Active
msb← msb.next;
msb.msgSet← DeclareMsgSet[msb.selector.name].msgSet;  -- Deleted
prevMsb← msb;
msb← msb.next;
DO
IF elT=NIL OR msb=NIL THEN EXIT;
ms← elT.first;
IF EqEntities[ms, deletedMsgSet] OR EqEntities[ms, activeMsgSet] THEN
{ elT← elT.rest; LOOP};
ms2← DeclareMsgSet[msb.selector.name, OldOnly].msgSet;
IF ms2=NIL THEN  -- msgSet was destroyed
{ prevMsb.next← msb.next; DeleteMSB[msb]; msb← prevMsb.next; LOOP};
IF EqEntities[ms, ms2] THEN
{ msb.msgSet← ms; prevMsb← msb; msb← msb.next; elT← elT.rest; LOOP};
there was a new msgset created
IF newMS = NIL THEN newMS← lastNewMS← CONS[ms, NIL]
ELSE lastNewMS← lastNewMS.rest← CONS[ms, NIL];
elT← elT.rest;
ENDLOOP;
IF msb#NIL THEN   -- delete these guys (ran out of msgSets)
DO
prevMsb.next← msb.next;
IF msb = lastMsgSetButton THEN lastMsgSetButton← prevMsb;
DeleteMSB[msb];
IF (msb← prevMsb.next)=NIL THEN EXIT;
ENDLOOP;
IF newMS#NIL THEN   -- add these at end
FOR nms: LIST OF MsgSet← newMS, nms.rest UNTIL nms=NIL DO
AddMSButton[nms.first, GetName[nms.first]];
ENDLOOP;
IF elT # NIL THEN   -- more to add
FOR elT← elT, elT.rest UNTIL elT=NIL DO
AddMSButton[elT.first, GetName[elT.first]];
ENDLOOP;
END;
DeselectMsgSet: PROC[msbH: MsgSetButton] =
BEGIN
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;
Buttons.SetDisplayStyle[msbH.selector, $BlackOnWhite];
RETURN
};
msb← msb2;
ENDLOOP;
END;
MSDisplay: PROC[msb: MsgSetButton, shift: BOOL] =
BEGIN OPEN ViewerOps;
msV: Viewer← msb.msViewer;
IF (msV # NIL) AND ~msV.destroyed THEN
{IF msV.iconic THEN OpenIcon[msV, shift]
ELSE IF shift THEN GrowViewer[msV] ELSE PaintViewer[msV, all]
}
ELSE
{ msb.msViewer←
WalnutMsgOps.BuildMsgSetDisplayer[msb.msgSet, msb.selector.name, shift];
WalnutMsgOps.MsgSetInViewer[NIL, msb.msgSet, msb.msViewer]
};
END;
FindMSBForMsgSet: PUBLIC PROC[msgSet: MsgSet] RETURNS[MsgSetButton] =
BEGIN
FOR msb: MsgSetButton← firstMsgSetButton, msb.next UNTIL msb = NIL DO
IF EqEntities[msb.msgSet, msgSet] THEN
{ IF msb.msViewer # NIL AND msb.msViewer.destroyed THEN msb.msViewer← NIL;
RETURN[msb];
}
ENDLOOP;
RETURN[NIL];
END;
END.