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 SelectMsgSetProc: TiogaButtons.TiogaButtonProc = { 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; }; selectedMsgSetButtons _ msbH; TiogaButtons.ChangeButtonLooks[ button: button, addLooks: msbSelectedLooks, removeLooks: msbDefaultLooks ]; 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]; 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] = { 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] = { 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 ]; 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. DWalnutMsgSetButtonsImpl.mesa Copyright c 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) 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. IF red THEN deselect all & select this one; IF yellow then display; IF blue THEN toggle whether selected or not Here we actually select the given button Fix up the icon, if necessary calculate how big the area for msgSet buttons should be if msgSet is Active, just destroy viewer, but not button * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * assumes msgSet does not already have a button; adds it after prevMsb Fix up the icon, if necessary Κ $˜šΟb™Icodešœ Οmœ1™Jšœ ˜ JšœŸœ'˜DJšœ Ÿœ˜šœŸœΦ˜πJ˜——šœŸœŸ˜&šŸ˜Jšœ˜JšœM˜MJšœ8˜8—JšŸœ%˜,J˜—JšŸœŸœ/˜9J˜JšŸœŸœŸœ˜JšœŸœ˜$Jšœ Ÿœ˜-J˜JšœŸœ˜ JšœŸœŸœ˜ J˜JšœŸœ Ÿœ˜$šœŸœŸœ˜JšœG˜G—šœŸ œ˜JšœJ˜J—Jšœ Ÿœ˜Jšœ Ÿœ˜Jšœ Ÿœ˜*J˜JšœŸœŸœΟc*˜\JšœŸœŸœ '˜WJ˜JšœŸœŸœ %˜UJšœŸœŸœ $˜SJ˜K˜š ™ šœ;™;KšœJ™J—™K™——K™™IKšœ!™!Kšœ#™#K™Kšœ™—Kšœ[™[˜šΟnœ"˜2JšœC™CJšœ+™+Jšœ#Ÿœ ˜2JšœŸœ ˜(J˜J˜šŸœŸœŸœ˜'Jšœ&˜&JšŸœ˜Jšœ˜—J˜šŸœŸœ˜Jšœ˜JšŸœ˜Jšœ˜—J˜šŸœŸœ ˜5šŸœ!ŸœŸœ˜-JšœŸœ˜šŸ˜Kšœo˜ošŸœŸœŸ˜#JšŸœ˜—JšœŸœ˜J˜ JšŸœ˜—J˜—J˜—šŸœ /˜7šŸœ+ŸœŸœŸ˜>šŸœ Ÿœ 6˜KJšœ˜JšŸœ˜Jšœ˜—JšŸœ˜—J˜&J˜—J˜Jšœ(™(J™J˜Kšœk˜kK˜Kšœ™Jšœ˜Jšœ˜—J˜š‘œŸœ O˜išŸœŸœ˜šŸœŸœŸœ˜%KšœŸœ˜K˜"K˜$K˜—šŸœ˜JšœŸœ%˜1J˜šŸœBŸœŸœŸ˜WK˜/KšŸœ˜—K˜K˜ K˜"K˜—K˜šŸœ"Ÿœ#Ÿ˜NKšœ˜—šŸ˜Kšœ˜—K˜—J˜——˜š‘œŸœŸœ˜"JšœŸœŸœŸœ˜J˜J˜JšœŸœŸœ˜JšœŸœ˜ JšœŸœ˜JšœŸœ˜Jšœ0˜0J˜šŸœŸœŸ˜šŸœŸœ˜"Jš '˜'šŸœ1ŸœŸœŸ˜DšŸœŸœŸœ˜šŸœŸœ˜ JšœŸœ˜Jšœ˜J˜—JšŸœ6˜:J˜JšŸœ !˜@—JšŸœ˜—JšŸœ˜—Jšœ˜—J˜Jšœ:Ÿœ˜@J˜Jšœ7™7šŸ˜Jšœ Ÿœ:˜GšŸœŸœ˜šœ ŸœŸœŸœ˜IJšŸœ5˜9—JšœŸœ˜"š ŸœŸœŸœŸœŸœŸœŸ˜3Jšœ- ˜BJšŸœ˜—Jšœ%˜%Jšœ)˜)šŸœŸœ ˜"JšŸœŸœŸœ˜5—J˜—Jšœ)˜)—JšŸœ˜J˜JšŸœŸœŸœ "˜Zšœ+˜+šœ3˜3Jšœ*Ÿœ˜3——Jšœ/˜/J˜šŸœ;Ÿœ˜C˜;Jšœ7˜7Jšœ*Ÿœ˜1—˜+J˜7Jšœ Ÿœ˜—Jšœ6˜6Jšœ'˜'J˜—Jšœ˜šœ˜JšŸœ>˜A—J˜šœ˜JšœB˜B—Jšœ˜J˜JšœHŸœ˜OJšœI˜Iš ŸœŸœŸœŸœŸœŸœŸ˜<šŸœ<ŸœŸ˜Hšœ-ŸœŸ˜8Jšœ˜——JšŸœ˜—Jšœ˜——˜š ‘œŸœŸœŸœŸœŸœ˜FšŸœ9ŸœŸœŸ˜LJšœŸœ ˜JšŸœ˜—Jšœ˜——˜š ‘œŸœŸœŸœ Ÿœ˜AJšœ˜Jšœ,˜,šŸ˜Jšœ%˜%šŸœ ŸœŸ˜Jšœ*Ÿœ˜0—šŸœ2Ÿ˜8Jšœ)Ÿœ˜/—Jšœ˜JšŸœ˜—šŸœŸœ ˜:Jšœ-˜-—Jšœ˜——˜š‘œŸœŸœ Ÿœ˜1Jšœ8™8˜*JšŸœ1ŸœŸœŸ˜FšŸœ%ŸœŸ˜2˜JšŸœŸœŸœŸœ˜BšŸœ/Ÿ˜5JšœŸœŸœ˜—J˜J˜J˜+J˜&JšŸ˜—J˜J˜—JšŸœ˜—Jšœ˜——˜š‘œŸœŸœ˜(JšœŸœ˜šŸœ1ŸœŸœŸ˜DJšŸœŸœŸœ'˜AJšœŸœ˜—JšŸœ˜JšœŸœ˜˜;J˜DJšœŸœ˜—˜+J˜7Jšœ Ÿœ˜—Jšœ(Ÿœ˜/JšœŸœ˜Jšœ'˜'J˜&Jšœ˜——˜š ‘œŸœŸœ ŸœŸœŸœ˜=Jš œŸœ ŸœŸœŸœ˜$Jš o˜oJšœŸœŸœ˜JšŸœ ŸœŸœŸœ ˜%š Ÿœ ŸœŸœŸœŸœŸœŸ˜QJšœ0˜0šŸœŸœŸœ˜Jšœ Ÿœ˜,JšŸ˜J˜—šœ˜Jšœ˜Jšœ ŸœŸœŸœ˜)Jšœ˜—JšœŸœ˜JšŸœ˜—J˜šŸœŸœŸ˜-K˜#—Jšœ˜—J˜J™FJ˜š ‘ œŸœ ŸœŸœŸœ˜OJšŸœ˜JšœD™DJ˜)J˜šŸœ Ÿ˜JšœI˜IJšŸœ˜—J˜JšœŸœE˜Ošœ$˜$Jšœ.˜.JšœC˜C—Jšœ˜Jšœ˜Jšœ˜Jšœ˜——˜š‘œŸœ˜,J˜*J˜šŸœ)ŸœŸœŸ˜=šŸœ Ÿœ ˜3J˜šŸœŸ˜$Jšœ&˜&—JšœŸœ˜Kšœp˜pK˜Kšœ™Jšœ˜JšŸ˜J˜—J˜ JšŸœ˜—Jšœ˜——˜š‘ œŸœŸœ˜3J˜šŸœŸœŸœŸ˜&šœŸœ Ÿœ˜3šŸœŸœŸœ˜,JšŸœ"˜&———JšŸœ>˜BJšœ˜——˜š ‘ œŸœŸœ ŸœŸœ˜>JšŸœ1ŸœŸœŸ˜FšŸœ%ŸœŸœ˜8JšŸœ˜—JšŸœŸœ˜ Jšœ˜——J˜JšŸœ˜J˜—…—*B=ͺ