<> <> <> <> <<>> <> <> <> <> <> <<(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 <> <> <> <> <> <<>> <> <> <> <> <> <> 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.