% file msc.sty % LaTeX macros to draw message sequence charts % % RCS version: $Id: msc.sty,v 1.1 2000/06/19 10:07:22 lamarre Exp $ % % Copyright S. Mauw and V. Bos % Eindhoven University of Technology % P.O. Box 513 % 5600 MB Eindhoven % The Netherlands % Email: sjouke@win.tue.nl, vbos@win.tue.nl % Updates via: http://www.win.tue.nl/cs/fm/sjouke/mscpackage.html % \def\mscdate{1999/07/19}% update this whenever this file changes \def\mscversion{1.47}% update this whenever a new version is ready \NeedsTeXFormat{LaTeX2e}% \ProvidesPackage{msc}[\mscdate, v\mscversion] \typeout{msc version \mscversion. (\mscdate)} \RequirePackage{pstricks,calc,ifthen} % % msc lengths % First the customizable lengths: \newlength{\topheaddist}% distance between top of head symbols and frame \newlength{\instheadheight}% height of head symbols \newlength{\firstlevelheight}% height of level just below head symbols \newlength{\levelheight}% height of a level \newlength{\lastlevelheight}% height of level just above foot symbols \newlength{\instfootheight}% height of foot symbols \newlength{\bottomfootdist}% distance between bottom of foot symbol and frame \newlength{\instwidth}% width of header and foot symbols \newlength{\instdist}% distance between (vertical) instance lines \newlength{\envinstdist}% distance between environments and nearest instance line \newlength{\topmscnamedist}% distance between top of frame and (top of) msc title \newlength{\selfmesswidth}% length of horizontal arms of self messages \newlength{\labeldist}% distance between labels and message lines or head symbol boxes \newlength{\coregionbarwidth}% width of coregion bars, preferably less than \instwidth \newlength{\lostsymbolradius}% radius of the lost and found symbols \newlength{\timerwidth}% width of the timer symbols \newlength{\stopwidth}% width of the stop symbol \newlength{\actionheight}% height of action symbols \newlength{\actionwidth}% width of action symbol \newlength{\conditionheight}% height of condition symbols \newlength{\conditionoverlap}% overlap of condition symbol \newlength{\referenceoverlap}% overlap of reference symbol \newlength{\inlineoverlap}% overlap of inline symbol % % Now the internal lengths \newlength{\tmp@X} \newlength{\tmp@Y} \newlength{\tmp@Xa} \newlength{\tmp@Ya} \newlength{\tmp@Xb} \newlength{\tmp@Yb} \newlength{\msc@currentheight} \newlength{\msc@currentwidth} \newlength{\msc@totalwidth} \newlength{\msc@totalheight} % % some internal offsets \def\msc@headoffset{\topheaddist+\instheadheight+\firstlevelheight} \def\msc@leveloffset{0}% \def\mscscalefactor{1}% \newcommand{\setmscscale}[1]{\def\mscscalefactor{#1}}% % % Command to change the footer color (legal values are black, gray, % lightgray, and white) \def\setfootcolor#1{\def\msc@footcolor{#1}} % % And some internal counters \newcounter{mscinstcnt} \newcounter{tmpcnt} % % \selfmesslabelpos defines the position of message labels of % self messages. The default value is "l" (left) other value(s) are "r" (right) \def\selfmesslabelpos{l} % % \msc@selfmesslabelpos is the internal variant of \selfmesslabelpos % This internal variant is used by the actual drawing commands for self messages \def\msc@selfmesslabelpos{l} % % \msc@setselfmesslabelpos sets the internal \mes@selfmesslabelpos \def\msc@setselfmesslabelpos#1{ \ifthenelse{\not\(\equal{#1}{l} \or \equal{#1}{r}\)}{% \msc@unknownselfmesslabelposerr{#1}}{% else \def\msc@selfmesslabelpos{#1}% }% } % % \dummyinst declares a dummy msc-instance and does not draws its head symbol % nor its instance axis until an instance create is encountered. % #1: nickname that can be used in \mess % % Some commands are defined as well (INSTNR is the arabic % representation of the instance number): % \instnicknameINSTNR: returns the nickname of instance INSTNR % \instxposINSTNR: returns the x-position of instance with nickname #1 % \instyposINSTNR: returns the last y-position of instance with nickname #1 % \instlinestyle#1: the line style (dashed or solid) of instance with nickname #1 \def\dummyinst#1{% user command to declare instances \@ifundefined{mscinst#1}{% \ifthenelse{\value{mscinstcnt}=2}{% Aha: this is the first msc instance, so, add the \addtolength{\msc@currentwidth}{\envinstdist}% left \envinstdist to \currentwidth }{\relax}% non-first inst, just relax % make an instance with empty inside name and empty above name: \msc@declinst{#1}{\relax}{\relax}% \setlength{\tmp@X}{\msc@instxpos{#1}}% % update the x position of the right environment: \setlength{\tmp@X}{\msc@currentwidth+\envinstdist}% \msc@setinstxpos{envright}{\the\tmp@X} % update the current width of the msc: \addtolength{\msc@currentwidth}{\instdist}% % make y-pos undefined, to make sure that no instance line will be drawn \msc@setinstypos{#1}{undefined}% --added sm }{% else: nickname #1 already defined! \msc@nicknamedefinederr{#1}% } } % % \declinst declares a new msc-instance and draws its head symbol % #1: nickname that can be used in \mess % #2: name of the instance (above instance head symbol) % #3: name of the instance (inside instance head symbol) % % Some commands are defined as well (INSTNR is the arabic % representation of the instance number): % \instabname#1: `above name' of instance with nickname #1 % \instinname#1: `inside name' of instance with nickname #1 % \instnicknameINSTNR: returns the nickname of instance INSTNR % \instxposINSTNR: returns the x-position of instance with nickname #1 % \instyposINSTNR: returns the last y-position of instance with nickname #1 % \instlinestyle#1: the line style (dashed or solid) of instance with nickname #1 \def\declinst#1#2#3{% user command to declare instances \@ifundefined{mscinst#1}{% \ifthenelse{\value{mscinstcnt}=2}{% Aha: this is the first msc instance, so, add the \addtolength{\msc@currentwidth}{\envinstdist}% left \envinstdist to \currentwidth }{\relax}% non-first inst, just relax \msc@declinst{#1}{#2}{#3}% \msc@drawinstancehead{#1}{#2}{#3}% \setlength{\tmp@X}{\msc@instxpos{#1}}% % update the x position of the right environment: \setlength{\tmp@X}{\msc@currentwidth+\envinstdist}% \msc@setinstxpos{envright}{\the\tmp@X} % update the current width of the msc: \addtolength{\msc@currentwidth}{\instdist}% }{% else: nickname #1 already defined! \msc@nicknamedefinederr{#1}% } } % % \def\msc@declinst#1#2#3{% internal command to declare instances \@ifundefined{mscinst#1}{% \@namedef{mscinst#1}{\relax}% \expandafter\def\csname instabname#1\endcsname{#2}% `above name' \expandafter\def\csname instinname#1\endcsname{#3}% `inside name' \expandafter\def\csname instnickname\arabic{mscinstcnt}\endcsname{#1}% % the x position of an instance, \instxpos#1, is stored as a string, not as % a TeX-length, since that would use up too much of TeX limited number of % length-registers. % However, this means we first have to calculate the x-pos, and then % assign the string representation of the result to \instxpos#1: \setlength{\tmp@X}{\msc@currentwidth}% \expandafter\edef\csname instxpos#1\endcsname{\the\tmp@X}% \setlength{\tmp@Y}{\topheaddist+\instheadheight}% \expandafter\edef\csname instypos#1\endcsname{\the\tmp@Y}% \expandafter\def\csname instlinestyle#1\endcsname{solid}% \stepcounter{mscinstcnt}% }{% else, #1 already defined \msc@nicknamedefinederr{#1}% } } % % \msc@instnickname gets the nickname of msc instance with number #1 % (This macro is used in \msc@drawinstancelevels) \def\msc@instnickname#1{% \csname instnickname\arabic{#1}\endcsname% } % % \msc@instxpos gets the x position (i.e., horizontal position) of the % msc instance with nickname #1. \def\msc@instxpos#1{% \expandafter\@ifundefined{mscinst#1}{% \msc@instundefinederr{#1}}{% else, #1 is defined % \def\msc@tmpexp{instxpos#1}% \expandafter\csname instxpos#1\endcsname}% } % % \msc@setinstxpos sets the x position of instance with nickname #1 to % the string #2 \def\msc@setinstxpos#1#2{% \expandafter\@ifundefined{mscinst#1}{% \msc@instundefinederr{#1}}{% else, #1 is defined \expandafter\edef\csname instxpos#1\endcsname{#2}% }% } % % \msc@instypos gets the last y position (i.e., vertical position) of the % msc instance with nickname #1. \def\msc@instypos#1{% \expandafter\@ifundefined{mscinst#1}{% \msc@instundefinederr{#1}}{% else, #1 is defined \csname instypos#1\endcsname}% } % % \msc@setinstypos sets the last y position of instance with nickname #1 to % the string #2 \def\msc@setinstypos#1#2{% \expandafter\@ifundefined{mscinst#1}{% \msc@instundefinederr{#1}}{% else, #1 is defined \expandafter\edef\csname instypos#1\endcsname{#2}% }% } % % Change \instlinestyle command of msc instance with ninkname #1 into #2 % #2 should be one of: solid, dashed, or dotted \def\msc@setinstlinestyle#1#2{% \expandafter\@ifundefined{mscinst#1}{% \msc@instundefinederr{#1}}{% else, #1 is defined \ifthenelse{\not\(\equal{#2}{solid} \or \equal{#2}{dashed} \or \equal{#2}{dotted}\)}{% unknown linestyle \msc@unknownlinestyleerr{#2}}{% \expandafter\def\csname instlinestyle#1\endcsname{#2}% }% }% } % % \msc@instlinestyle returns the linestyle of instance with nickname #1 \def\msc@instlinestyle#1{% \expandafter\@ifundefined{mscinst#1}{% \msc@instundefinederr{#1}}{% else, #1 is defined \csname instlinestyle#1\endcsname}% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5 % % CREATE % % \create creates a new msc-instance and draws its head symbol % #1: text above creation message % #2: nickname of creating instance % #3: nickname of created instance % #4: name of the instance (above instance head symbol) % #5: name of the instance (inside instance head symbol) % % Some commands are defined as well (INSTNR is the arabic % representation of the instance number): % \instabname#3: `above name' of instance with nickname #3 % \instinname#3: `inside name' of instance with nickname #3 % \instlinestyle#3: the line style (dashed or solid) of instance with nickname #3 \def\create#1#2#3#4#5{% \expandafter\@ifundefined{mscinst#2}{% \msc@instundefinederr{#2}}{% else, #2 is defined \expandafter\@ifundefined{mscinst#3}{% \msc@instundefinederr{#3}}{% else, #3 is defined \expandafter\def\csname instabname#3\endcsname{#4}% `above name' \expandafter\def\csname instinname#3\endcsname{#5}% `inside name' % draw the instance header symbol \setlength{\tmp@X}{\msc@instxpos{#3}}% x-center head box \setlength{\tmp@Y}{\msc@currentheight+\msc@headoffset}% y-center head box \setlength{\tmp@Xa}{-0.5\instwidth+\tmp@X}% x-upperleft head box \setlength{\tmp@Ya}{\msc@currentheight+\msc@headoffset-0.5\instheadheight}% \setlength{\tmp@Xb}{\tmp@Xa+\instwidth}% x-lowerright head box \setlength{\tmp@Yb}{\tmp@Ya+\instheadheight}% y-lowerright head box \psframe(\tmp@Xa,-\tmp@Ya)(\tmp@Xb,-\tmp@Yb)% \rput[B](\tmp@X,-\tmp@Ya){\raisebox{\labeldist}{\makebox[0pt][c]{#4}}}% \rput[B](\tmp@X,-\tmp@Y){\raisebox{-.5ex}{\makebox[0pt][c]{#5}}}% % redefine the instance's y position \setlength{\tmp@Y}{\msc@currentheight+0.5\instheadheight+\msc@headoffset}% \msc@setinstypos{#3}{\the\tmp@Y}% % draw creation arrow \setlength{\tmp@Xa}{\msc@instxpos{#2}}% \setlength{\tmp@Ya}{\msc@currentheight+\msc@headoffset}% \setlength{\tmp@Yb}{\msc@currentheight+\msc@headoffset}% \setlength{\tmp@Xb}{\msc@instxpos{#3}}% \ifthenelse{\lengthtest{\tmp@Xa < \tmp@Xb}}{% arrow comes from the left \setlength{\tmp@Xb}{\tmp@Xb-0.5\instwidth}% }{% else arrow comes from the right \setlength{\tmp@Xb}{\tmp@Xb+0.5\instwidth}% }% \msc@drawmessage{\tmp@Xa}{\tmp@Ya}{\tmp@Xb}{\tmp@Yb}{#1}{dashed}% }% }% } % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % INLINE EXPRESSIONS (inlines) % % % \inlineestart creates an inline expression at the current level % [#1]: overlap % #2: nickname of the inline % #3: text of the inline % #4: first instance of the inline % #5: final instance of the inline \newcommand{\inlinestart}[5][\inlineoverlap]{\msc@declinline{#1}{#2}{#3}{#4}{#5}}% % % \inlineend draws and ends the inline expression with nickname #1 % \newcommand{\inlineend}{% \@ifstar{\msc@inlineends}{\msc@inlineend}} % % \inlineseparator draws a ``separator'' (horizontal dashed line) through % inline expression with nickname #1 \newcommand{\inlineseparator}[1]{% \expandafter\@ifundefined{mscinl#1}{% \msc@inlundefinederr{#1}}{% else, #1 is defined \setlength{\tmp@Y}{\msc@currentheight+\msc@headoffset}% \psline[linestyle=dashed](\msc@inlulx{#1},-\tmp@Y)(\msc@inllrx{#1},-\tmp@Y)% }% } % % internal commands to implement the inline expressions: % \def\msc@declinline#1#2#3#4#5{% \@ifundefined{mscinl#2}{% \@ifundefined{mscinst#4}{% #4 is not an instance nickname \msc@instundefinederr{#4}}{% \@ifundefined{mscinst#5}{% #5 is not an instance nickname \msc@instundefinederr{#5}}{% \ifthenelse{\lengthtest{\msc@instxpos{#4}>\msc@instxpos{#5}}}{% \msc@inlfirstlasterror{#2}{#4}{#5}}{% \@namedef{mscinl#2}{\relax}% \expandafter\def\csname inltext#2\endcsname{#3}% \setlength{\tmp@X}{\msc@instxpos{#4}-#1}% \expandafter\edef\csname inlulx#2\endcsname{\the\tmp@X}% \expandafter\edef\csname inluly#2\endcsname{\the\msc@currentheight}% \setlength{\tmp@X}{\msc@instxpos{#5}+#1}% \expandafter\edef\csname inllrx#2\endcsname{\the\tmp@X}% \expandafter\edef\csname inllry#2\endcsname{undefined}% % two additional instances are defined \msc@declinst{#2left}{\relax}{\relax}% left of inline \msc@setinstxpos{#2left}{\msc@inlulx{#2}}% \msc@setinstypos{#2left}{undefined}% no instance line drawing \msc@declinst{#2right}{\relax}{\relax}% left of inline \msc@setinstxpos{#2right}{\msc@inllrx{#2}}% \msc@setinstypos{#2right}{undefined}% no instance line drawing }% }% }% }{% nickname #2 already defined \msc@nicknamedefinederr{#2}% }% } % % \msc@inlulx gets the upper-left x-position of inline with nickname #1. \def\msc@inlulx#1{% \expandafter\@ifundefined{mscinl#1}{% \msc@inlundefinederr{#1}}{% else, #1 is defined \csname inlulx#1\endcsname% }% } % % \msc@inluly gets the upper-left y-position of inline with nickname #1. \def\msc@inluly#1{% \expandafter\@ifundefined{mscinl#1}{% \msc@inlundefinederr{#1}}{% else, #1 is defined \csname inluly#1\endcsname% }% } % % \msc@inllrx gets the lower-right x-position of inline with nickname #1. \def\msc@inllrx#1{% \expandafter\@ifundefined{mscinl#1}{% \msc@inlundefinederr{#1}}{% else, #1 is defined \csname inllrx#1\endcsname% }% } % % \msc@inllry gets the lower-right y-position of inline with nickname #1. \def\msc@inllry#1{% \expandafter\@ifundefined{mscinl#1}{% \msc@inlundefinederr{#1}}{% else, #1 is defined \csname inllry#1\endcsname% }% } % % \msc@inltext gets the text of inline with nickname #1 \def\msc@inltext#1{% \expandafter\@ifundefined{mscinl#1}{% \msc@inlundefinederr{#1}}{% else, #1 is defined \csname inltext#1\endcsname% }% } % % \msc@inlineend completes the inline with nickname #1 % (the bottom line is solid) \def\msc@inlineend#1{% \expandafter\@ifundefined{mscinl#1}{% \msc@inlundefinederr{#1}}{% else, #1 is defined \expandafter\edef\csname inllry#1\endcsname{\the\msc@currentheight}% \setlength{\tmp@Xa}{\msc@inlulx{#1}}% \setlength{\tmp@Ya}{\msc@inluly{#1}+\msc@headoffset}% \setlength{\tmp@Xb}{\msc@inllrx{#1}}% \setlength{\tmp@Yb}{\msc@inllry{#1}+\msc@headoffset}% %% Debug info: % \typeout{(\tmp@Xa,-\tmp@Ya)(\tmp@Xb,-\tmp@Yb)}% \psframe(\tmp@Xa,-\tmp@Ya)(\tmp@Xb,-\tmp@Yb)% \settowidth{\tmp@X}{\msc@inltext{#1}}% \setlength{\tmp@X}{1.1\tmp@X+\labeldist}% \settoheight{\tmp@Y}{\msc@inltext{#1}}% \setlength{\tmp@Y}{1.1\tmp@Y+\labeldist}% \setlength{\tmp@Xb}{\tmp@X+\labeldist}% \setlength{\tmp@Yb}{\tmp@Y+\labeldist}% \rput(\tmp@Xa,-\tmp@Ya){% \rput[tl](\labeldist,-\labeldist){\msc@inltext{#1}}% \psline(0,-\tmp@Yb)(\tmp@X,-\tmp@Yb)(\tmp@Xb,-\tmp@Y)(\tmp@Xb,0)% }% }% } % % \msc@inlineends completes the inline with nickname #1 % (the bottom line is dashed) \def\msc@inlineends#1{% \expandafter\@ifundefined{mscinl#1}{% \msc@inlundefinederr{#1}}{% else, #1 is defined \expandafter\edef\csname inllry#1\endcsname{\the\msc@currentheight}% \setlength{\tmp@Xa}{\msc@inlulx{#1}}% \setlength{\tmp@Ya}{\msc@inluly{#1}+\msc@headoffset}% \setlength{\tmp@Xb}{\msc@inllrx{#1}}% \setlength{\tmp@Yb}{\msc@inllry{#1}+\msc@headoffset}% %% Debug info: % \typeout{(\tmp@Xa,-\tmp@Ya)(\tmp@Xb,-\tmp@Yb)}% % first the solid part of the inline expression: \psline(\tmp@Xa,-\tmp@Yb)(\tmp@Xa,-\tmp@Ya)(\tmp@Xb,-\tmp@Ya)(\tmp@Xb,-\tmp@Yb)% % then the dashed bottom line: \psline[linestyle=dashed](\tmp@Xa,-\tmp@Yb)(\tmp@Xb,-\tmp@Yb) \settowidth{\tmp@X}{\msc@inltext{#1}}% \setlength{\tmp@X}{1.1\tmp@X+\labeldist}% \settoheight{\tmp@Y}{\msc@inltext{#1}}% \setlength{\tmp@Y}{1.1\tmp@Y+\labeldist}% \setlength{\tmp@Xb}{\tmp@X+\labeldist}% \setlength{\tmp@Yb}{\tmp@Y+\labeldist}% \rput(\tmp@Xa,-\tmp@Ya){% \rput[tl](\labeldist,-\labeldist){\msc@inltext{#1}}% \psline(0,-\tmp@Yb)(\tmp@X,-\tmp@Yb)(\tmp@Xb,-\tmp@Y)(\tmp@Xb,0)% }% }% } % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % REFERENCES % % % \referencestart creates an msc reference at the current level % [#1] : overlap % #2: nickname of the reference % #3: text of the reference % #4: first instance of the reference % #5: final instance of the reference \newcommand{\referencestart}[5][\referenceoverlap]{% \msc@declreference{#1}{#2}{#3}{#4}{#5}% \setcounter{tmpcnt}{0}% \msc@reffindfirst{#2}{\msc@drawtorefaux}% } % % \referenceend draws and ends the reference with nickname #1 \newcommand{\referenceend}[1]{% \msc@drawreference{#1}% \setcounter{tmpcnt}{0}% \setlength{\tmp@Y}{\msc@currentheight+\msc@headoffset}% \msc@reffindfirst{#1}{\msc@refresetypos{\the\tmp@Y}}% } % % internal commands to implement references: % \def\msc@declreference#1#2#3#4#5{% \@ifundefined{mscref#2}{% \@ifundefined{mscinst#4}{% #4 is not an instance nickname \msc@instundefinederr{#4}}{% \@ifundefined{mscinst#5}{% #5 is not an instance nickname \msc@instundefinederr{#5}}{% \ifthenelse{\lengthtest{\msc@instxpos{#4}>\msc@instxpos{#4}}}{% \msc@reffirstlasterror{#2}{#4}{#5}}{% \@namedef{mscref#2}{\relax}% \expandafter\def\csname reftext#2\endcsname{#3}% \setlength{\tmp@X}{\msc@instxpos{#4}-#1}% \expandafter\edef\csname refulx#2\endcsname{\the\tmp@X}% \expandafter\edef\csname refuly#2\endcsname{\the\msc@currentheight}% \setlength{\tmp@X}{\msc@instxpos{#5}+#1}% \expandafter\edef\csname reflrx#2\endcsname{\the\tmp@X}% \expandafter\edef\csname reflry#2\endcsname{undefined}% \expandafter\def\csname reffirst#2\endcsname{#4}% \expandafter\def\csname reffinal#2\endcsname{#5}% % two additional instances are defined \msc@declinst{#2left}{\relax}{\relax}% left of reference \msc@setinstxpos{#2left}{\msc@refulx{#2}}% \msc@setinstypos{#2left}{undefined}% no instance line drawing \msc@declinst{#2right}{\relax}{\relax}% left of reference \msc@setinstxpos{#2right}{\msc@reflrx{#2}}% \msc@setinstypos{#2right}{undefined}% no instance line drawing }% }% }% }{% nickname #1 already defined \msc@nicknamedefinederr{#2}% }% } % % \msc@refulx gets the upper-left x-position of reference with nickname #1. \def\msc@refulx#1{% \expandafter\@ifundefined{mscref#1}{% \msc@refundefinederr{#1}}{% else, #1 is defined \csname refulx#1\endcsname% }% } % % \msc@refuly gets the upper-left y-position of reference with nickname #1. \def\msc@refuly#1{% \expandafter\@ifundefined{mscref#1}{% \msc@refundefinederr{#1}}{% else, #1 is defined \csname refuly#1\endcsname% }% } % % \msc@reflrx gets the lower-right x-position of reference with nickname #1. \def\msc@reflrx#1{% \expandafter\@ifundefined{mscref#1}{% \msc@refundefinederr{#1}}{% else, #1 is defined \csname reflrx#1\endcsname% }% } % % \msc@reflry gets the lower-right y-position of reference with nickname #1. \def\msc@reflry#1{% \expandafter\@ifundefined{mscref#1}{% \msc@refundefinederr{#1}}{% else, #1 is defined \csname reflry#1\endcsname% }% } % % \msc@reftext gets the text of reference with nickname #1 \def\msc@reftext#1{% \expandafter\@ifundefined{mscref#1}{% \msc@refundefinederr{#1}}{% else, #1 is defined \csname reftext#1\endcsname% }% } % % \msc@reftext gets the nickname of the first instance of the reference with nickname #1 \def\msc@reffirst#1{% \expandafter\@ifundefined{mscref#1}{% \msc@refundefinederr{#1}}{% else, #1 is defined \csname reffirst#1\endcsname% }% } % % \msc@reftext gets the nickname of the final instance of the reference with nickname #1 \def\msc@reffinal#1{% \expandafter\@ifundefined{mscref#1}{% \msc@refundefinederr{#1}}{% else, #1 is defined \csname reffinal#1\endcsname% }% } % % \msc@drawreference completes the reference with nickname #1 \def\msc@drawreference#1{% \expandafter\@ifundefined{mscref#1}{% \msc@refundefinederr{#1}}{% else, #1 is defined \expandafter\edef\csname reflry#1\endcsname{\the\msc@currentheight}% \setlength{\tmp@Xa}{\msc@refulx{#1}}% \setlength{\tmp@Ya}{\msc@refuly{#1}+\msc@headoffset}% \setlength{\tmp@Xb}{\msc@reflrx{#1}}% \setlength{\tmp@Yb}{\msc@reflry{#1}+\msc@headoffset}% %% Debug info: % \typeout{(\tmp@Xa,-\tmp@Ya)(\tmp@Xb,-\tmp@Yb)}% \psframe[framearc=0.25](\tmp@Xa,-\tmp@Ya)(\tmp@Xb,-\tmp@Yb)% note: rounded corners \setlength{\tmp@X}{\tmp@Xb-\tmp@Xa}% \setlength{\tmp@Y}{\tmp@Yb-\tmp@Ya}% \rput(\tmp@Xa,-\tmp@Ya){% \rput[B](.5\tmp@X,-.5\tmp@Y){\raisebox{-.5ex}{\makebox[0pt][c]{\msc@reftext{#1}}}}% }% }% } % \def\msc@reffindfirst#1#2{% \ifthenelse{\value{tmpcnt} < \value{mscinstcnt}}{% % Debug info: % \typeout{(drawtoref) checking \msc@instnickname{tmpcnt}}% \ifthenelse{\equal{\msc@instnickname{tmpcnt}}{\msc@reffirst{#1}}}{% first instance found % Debug info: % \typeout{first found: \msc@instnickname{tmpcnt}}% #2{#1}}{% else, keep on looking \stepcounter{tmpcnt}% \msc@reffindfirst{#1}{#2}}}{% done ! all instances checked }% } % \def\msc@drawtorefaux#1{% \ifthenelse{\value{tmpcnt} < \value{mscinstcnt}}{% % Debug info: % \typeout{(drawtorefaux) checking \msc@instnickname{tmpcnt}}% \msc@drawinstanceline{\msc@instnickname{tmpcnt}}% \msc@setinstypos{\msc@instnickname{tmpcnt}}{undefined}% \ifthenelse{\equal{\msc@instnickname{tmpcnt}}{\msc@reffinal{#1}}}{% final instance found % Debug info: % \typeout{final found: \msc@instnickname{tmpcnt}}% }{% else, non-final \stepcounter{tmpcnt}% \msc@drawtorefaux{#1}}% }{% done ! all instances checked }% } % \def\msc@refresetypos#1#2{% \ifthenelse{\value{tmpcnt} < \value{mscinstcnt}}{% % Debug info: % \typeout{(drawtorefaux) checking \msc@instnickname{tmpcnt}} \msc@setinstypos{\msc@instnickname{tmpcnt}}{#1}% \ifthenelse{\equal{\msc@instnickname{tmpcnt}}{\msc@reffinal{#2}}}{% final instance found % Debug info: % \typeout{final found: \msc@instnickname{tmpcnt}}% }{% else, non-final \stepcounter{tmpcnt}% \msc@refresetypos{#1}{#2}}% }{% done ! all instances checked }% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % CO-REGIONS % % \coregionstart starts a coregion on instance #1 (nickname) in the current level. \def\coregionstart#1{\msc@coregionstartend{#1}{dashed}}% % \coregionend ends a coregion on instance #1 (nickname) in the current level. \def\coregionend#1{\msc@coregionstartend{#1}{solid}}% % % internal commands to implement co-regions: % \def\msc@coregionstartend#1#2{% \expandafter\@ifundefined{mscinst#1}{% \msc@instundefinederr{#1}}{% else, #1 is defined \msc@drawinstanceline{#1}% \msc@drawcoregionbar{#1}% \setlength{\tmp@Y}{\msc@currentheight+\msc@headoffset}% \msc@setinstypos{#1}{\the\tmp@Y}% \msc@setinstlinestyle{#1}{#2}% }% } % \def\msc@drawcoregionbar#1{% \expandafter\@ifundefined{mscinst#1}{% \msc@instundefinederr{#1}}{% else, #1 is defined \setlength{\tmp@Xa}{-.5\coregionbarwidth+\msc@instxpos{#1}}% \setlength{\tmp@Xb}{.5\coregionbarwidth+\msc@instxpos{#1}}% \setlength{\tmp@Ya}{\msc@currentheight+\msc@headoffset} \psline(\tmp@Xa,-\tmp@Ya)(\tmp@Xb,-\tmp@Ya)% }% } % % \messarrowscale sets the arrow scale \def\messarrowscale#1{\psset{arrowscale=#1}} % % \msc@setleveloffset sets the internal level offset \def\msc@setleveloffset#1{% \def\msc@leveloffset{#1}% } % % \mess has one optional argument to define the position of % the label of a self message. \newcommand{\mess}[1][\selfmesslabelpos]{% \msc@setselfmesslabelpos{#1}% \@messdispatcher{mess}% } % % \order has one optional argument to define the position of % the label of a self order. \newcommand{\order}[1][\selfmesslabelpos]{% \msc@setselfmesslabelpos{#1}% \@messdispatcher{order}{0}% } % % \@messdispatcher, \@oargmessdispatcher, and \@nooargmessdispatcher % together handle the different forms of the user comands \order and \mess. % % \@messdispatcher checks for an optional argument defining the level % offset. If the optional argument is present, \@oargmessdispatcher is % called, otherwise \@nooargmessdispatcher is called. % Both \@oargmessdispatcher and \@nooargmessdispatcher are dispatchers for % the macros: % \msc@selfmess % \msc@mess \def\@messdispatcher#1#2#3#4{% \@ifnextchar[{\@oargmessdispatcher{#1}{#2}{#3}{#4}}{\@nooargmessdispatcher{#1}{#2}{#3}{#4}}} % \def\@oargmessdispatcher#1#2#3#4[#5]{% \def\msc@a{#3}% \def\msc@b{#4}% \ifx\msc@a\msc@b% \msc@setleveloffset{#5}% \msc@selfmess{#1}{#2}{#3}% \else% \msc@setleveloffset{#5}% \msc@mess{#1}{#2}{#3}{#4}% \fi% } % % \@nooargmessdispatcher does not expect the optional level-offset argument, % but uses the default offset values to set \msc@leveloffset. \def\@nooargmessdispatcher#1#2#3#4{% \def\msc@a{#3}% \def\msc@b{#4}% \ifx\msc@a\msc@b% \msc@setleveloffset{1}% default level-offset value for self messages \msc@selfmess{#1}{#2}{#3}% \else% \msc@setleveloffset{0}% default level-offset value for non-self messages \msc@mess{#1}{#2}{#3}{#4}% \fi% } % % \@mess draws a message from `from-instance' to `to-instance' % #1: type of the message % #2: name of the message % #3: nickname from-instance % #4: nickname to-instance \def\msc@mess#1#2#3#4{% \expandafter\@ifundefined{mscinst#3}{% \msc@instundefinederr{#3}}{% else, #3 is defined \expandafter\@ifundefined{mscinst#4}{% \msc@instundefinederr{#4}}{% else, #4 is defined \setlength{\tmp@Xa}{\msc@instxpos{#3}}% \setlength{\tmp@Ya}{\msc@currentheight+\msc@headoffset}% \setlength{\tmp@Xb}{\msc@instxpos{#4}}% \setlength{\tmp@Yb}{\msc@currentheight+\msc@headoffset+\levelheight*\msc@leveloffset}% \msc@messtypeselection{#1}{\tmp@Xa}{\tmp@Ya}{\tmp@Xb}{\tmp@Yb}{#2}% }% }% } % % \msc@selfmess draws a self-message or a self-orderline on an instance. % #1: flag indicating if this is a message (mess) or an orderline (order) % #2: name of the message % #3: nickname of the instance \def\msc@selfmess#1#2#3{% \expandafter\@ifundefined{mscinst#3}{% \msc@instundefinederr{#3}}{% else, #3 is defined \setlength{\tmp@Xa}{\msc@instxpos{#3}}% \setlength{\tmp@Ya}{\msc@currentheight+\msc@headoffset}% \setlength{\tmp@Yb}{\tmp@Ya+\levelheight*\msc@leveloffset}% \setlength{\tmp@Y}{\tmp@Ya+0.5\tmp@Yb-0.5\tmp@Ya}% \ifthenelse{\equal{\msc@selfmesslabelpos}{l}}{% then left of instance \setlength{\tmp@Xb}{\tmp@Xa-\selfmesswidth}% \setlength{\tmp@X}{\tmp@Xb-\labeldist}% \def\msc@justification{r}% }{% else right of instance \setlength{\tmp@Xb}{\tmp@Xa+\selfmesswidth}% \setlength{\tmp@X}{\tmp@Xb+\labeldist}% \def\msc@justification{l} }% \ifthenelse{\equal{#1}{mess}}{% draw a self message \psline{->}(\tmp@Xa,-\tmp@Ya)(\tmp@Xb,-\tmp@Ya)(\tmp@Xb,-\tmp@Yb)(\tmp@Xa,-\tmp@Yb)% \rput(\tmp@X,-\tmp@Y){\makebox[0pt][\msc@justification]{#2}}% }{% else, draw a self orderline \psline[linestyle=dotted]{->}(\tmp@Xa,-\tmp@Ya)(\tmp@Xb,-\tmp@Ya)(\tmp@Xb,-\tmp@Y)% \psline[linestyle=dotted](\tmp@Xb,-\tmp@Y)(\tmp@Xb,-\tmp@Yb)(\tmp@Xa,-\tmp@Yb)% }% }% } % % \msc@messtypeselection selects on base of first argument if an % orderline or a message should be drawn \def\msc@messtypeselection#1#2#3#4#5#6{% \ifthenelse{\equal{#1}{mess}}{% \msc@drawmessage{#2}{#3}{#4}{#5}{#6}{normal}}{% else orderline \msc@draworder{#2}{#3}{#4}{#5} }% } % % \msc@draworder draws an orderline from (#1,#2) to (#3,#4) \def\msc@draworder#1#2#3#4{% \setlength{\tmp@Xa}{#1}% \setlength{\tmp@Ya}{#2}% \setlength{\tmp@Xb}{#3}% \setlength{\tmp@Yb}{#4}% \setlength{\tmp@X}{0.4\tmp@Xa+0.6\tmp@Xb}% \setlength{\tmp@Y}{0.4\tmp@Ya+0.6\tmp@Yb}% \psline[linestyle=dotted]{->}(\tmp@Xa,-\tmp@Ya)(\tmp@X,-\tmp@Y)% \psline[linestyle=dotted](\tmp@X,-\tmp@Y)(\tmp@Xb,-\tmp@Yb)% } % % \msc@drawmessage draws a message from (#1,#2) to (#3,#4) and puts % the label #5 near the message % #6 is either "dashed" or "normal" and determines drawing mode \def\msc@drawmessage#1#2#3#4#5#6{% \setlength{\tmp@Xa}{#1}% \setlength{\tmp@Ya}{#2}% \setlength{\tmp@Xb}{#3}% \setlength{\tmp@Yb}{#4}% \setlength{\tmp@X}{\tmp@Xb-\tmp@Xa}% \setlength{\tmp@Y}{\tmp@Yb-\tmp@Ya}% \ifthenelse{\lengthtest{\tmp@Y=0pt}}{% \def\msc@justification{c}% }{% else \ifthenelse{\(\lengthtest{\tmp@X<0pt} \and \lengthtest{\tmp@Y>0pt}\)% \or% \(\lengthtest{\tmp@X>0pt} \and \lengthtest{\tmp@Y<0pt}\)}{% \def\msc@justification{r}% }{% else \def\msc@justification{l}% }% }% \ifthenelse{\lengthtest{\tmp@Xa<\tmp@Xb}}{% \setlength{\tmp@X}{\tmp@Xa+0.5\tmp@Xb-0.5\tmp@Xa}}{% \setlength{\tmp@X}{\tmp@Xb+0.5\tmp@Xa-0.5\tmp@Xb}}% \ifthenelse{\lengthtest{\tmp@Ya<\tmp@Yb}}{% \setlength{\tmp@Y}{\tmp@Ya+0.5\tmp@Yb-0.5\tmp@Ya}}{% \setlength{\tmp@Y}{\tmp@Yb+0.5\tmp@Ya-0.5\tmp@Yb}}% \ifthenelse{\equal{#6}{normal}}{% draw normal line \psline{->}(\tmp@Xa,-\tmp@Ya)(\tmp@Xb,-\tmp@Yb)% }{ %else draw dashed line \psline[linestyle=dashed]{->}(\tmp@Xa,-\tmp@Ya)(\tmp@Xb,-\tmp@Yb)% }% \rput[B](\tmp@X,-\tmp@Y){\raisebox{\labeldist}{\makebox[0pt][\msc@justification]{#5}}}% % debugging info: % \message{(msg: #5, justification: \msc@justification)}% } % % \lost has one optional argument to define the position of % the label of a self message. \newcommand{\lost}[1][\selfmesslabelpos]{% \msc@setselfmesslabelpos{#1}% \def\msc@arrowdirection{->}% \def\msc@circlefillstyle{black}% \@lostfound{lost}% } % % \found has one optional argument to define the position of % the label of a self message. \newcommand{\found}[1][\selfmesslabelpos]{% \msc@setselfmesslabelpos{#1}% \def\msc@arrowdirection{<-}% \def\msc@circlefillstyle{white}% \@lostfound{found}% } % % \@lostfound draws lost and found messages % #1: type of the message (lost/found) % #2: name of the message % #3: name of the gate % #4: nickname of the instance \def\@lostfound#1#2#3#4{% \expandafter\@ifundefined{mscinst#4}{% \msc@instundefinederr{#4}}{% else, #4 is defined \setlength{\tmp@Xa}{\msc@instxpos{#4}}% \setlength{\tmp@Ya}{\msc@currentheight+\msc@headoffset}% \ifthenelse{\equal{\msc@selfmesslabelpos}{l}}{% then put label left \setlength{\tmp@Xb}{\tmp@Xa-\selfmesswidth}% \psline{\msc@arrowdirection}(\tmp@Xa,-\tmp@Ya)(\tmp@Xb,-\tmp@Ya)% \setlength{\tmp@X}{0.6\tmp@Xa+0.4\tmp@Xb}% \setlength{\tmp@Y}{\tmp@Ya-\lostsymbolradius-\labeldist}% \rput[B](\tmp@X,-\tmp@Y){\makebox[0pt][r]{#2}}% \setlength{\tmp@Xb}{\tmp@Xb-\lostsymbolradius}% \pscircle[fillstyle=solid,fillcolor=\msc@circlefillstyle]% (\tmp@Xb,-\tmp@Ya){\lostsymbolradius} \setlength{\tmp@X}{\tmp@Xb-\lostsymbolradius-\labeldist}% \setlength{\tmp@Y}{\tmp@Ya+0.5ex}% \rput[B](\tmp@X,-\tmp@Y){\makebox[0pt][r]{#3}}% }{% else, put label right \setlength{\tmp@Xb}{\tmp@Xa+\selfmesswidth}% \psline{\msc@arrowdirection}(\tmp@Xa,-\tmp@Ya)(\tmp@Xb,-\tmp@Ya)% \setlength{\tmp@X}{0.6\tmp@Xa+0.4\tmp@Xb}% \setlength{\tmp@Y}{\tmp@Ya-\lostsymbolradius-\labeldist}% \rput[B](\tmp@X,-\tmp@Y){\makebox[0pt][l]{#2}}% \setlength{\tmp@Xb}{\tmp@Xb+\lostsymbolradius}% \pscircle[fillstyle=solid,fillcolor=\msc@circlefillstyle]% (\tmp@Xb,-\tmp@Ya){\lostsymbolradius} \setlength{\tmp@X}{\tmp@Xb+\lostsymbolradius+\labeldist}% \setlength{\tmp@Y}{\tmp@Ya+0.5ex}% \rput[B](\tmp@X,-\tmp@Y){\makebox[0pt][l]{#3}}% }% }% } % % % \settimer has one optional argument to define the position of % the label of a self message. \newcommand{\settimer}[1][\selfmesslabelpos]{% \msc@setselfmesslabelpos{#1}% \@timer{set}% } % % % \timeout has one optional argument to define the position of % the label of a self message. \newcommand{\timeout}[1][\selfmesslabelpos]{% \msc@setselfmesslabelpos{#1}% \@timer{timeout}% } % % % \stoptimer has one optional argument to define the position of % the label of a self message. \newcommand{\stoptimer}[1][\selfmesslabelpos]{% \msc@setselfmesslabelpos{#1}% \@timer{stop}% } % % % \settimeout has one optional argument to define the position of % the label of a self message. \newcommand{\settimeout}[1][\selfmesslabelpos]{% \msc@setselfmesslabelpos{#1}% \@timerdispatcher{settimeout}% } % % % \setstoptimer has one optional argument to define the position of % the label of a self message. \newcommand{\setstoptimer}[1][\selfmesslabelpos]{% \msc@setselfmesslabelpos{#1}% \@timerdispatcher{setstoptimer}% } \def\@timerdispatcher#1#2#3{% \@ifnextchar[{\@oargtimerdispatcher{#1}{#2}{#3}}{\@nooargtimerdispatcher{#1}{#2}{#3}}} % \def\@oargtimerdispatcher#1#2#3[#4]{% \msc@setleveloffset{#4}% \@timer{#1}{#2}{#3}% } % \def\@nooargtimerdispatcher#1#2#3{% \msc@setleveloffset{2}% default level-offset value for combined timers \@timer{#1}{#2}{#3}% } % % % \@timer draws timers % #1: type of the timer (set/timeout/stop) % #2: label % #3: nickname of the instance \def\@timer#1#2#3{% \expandafter\@ifundefined{mscinst#3}{% \msc@instundefinederr{#3}}{% else, #3 is defined \setlength{\tmp@Xa}{\msc@instxpos{#3}}% \setlength{\tmp@Ya}{\msc@currentheight+\msc@headoffset}% \ifthenelse{\equal{\msc@selfmesslabelpos}{l}}{% point left of axis \setlength{\tmp@Xb}{\tmp@Xa-\selfmesswidth}% }{ % else point right of axis \setlength{\tmp@Xb}{\tmp@Xa+\selfmesswidth}% }% \ifthenelse{\equal{#1}{timeout}}{% draw an arrow \psline{<-}(\tmp@Xa,-\tmp@Ya)(\tmp@Xb,-\tmp@Ya)% }{ % else draw a line without arrow head \psline(\tmp@Xa,-\tmp@Ya)(\tmp@Xb,-\tmp@Ya)% }% \setlength{\tmp@X}{\tmp@Xb}% This looks clumsy - sm \setlength{\tmp@Y}{\tmp@Ya}% \msc@drawtimer{#1}{\tmp@X}{\tmp@Y}{\msc@selfmesslabelpos}{#2}% \ifthenelse{\equal{#1}{settimeout}}{% draw second part of settimeout \setlength{\tmp@Ya}{\tmp@Y+\levelheight*\msc@leveloffset}% \setlength{\tmp@Y}{\tmp@Y+0.75\timerwidth}% \psline{->}(\tmp@X,-\tmp@Y)(\tmp@X,-\tmp@Ya)(\msc@instxpos{#3},-\tmp@Ya)% }{ % else not settimeout \ifthenelse{\equal{#1}{setstoptimer}}{% draw second part of setstoptimer \setlength{\tmp@Ya}{\tmp@Y+\levelheight*\msc@leveloffset}% \setlength{\tmp@Y}{\tmp@Y+0.75\timerwidth}% \psline(\tmp@X,-\tmp@Y)(\tmp@X,-\tmp@Ya)(\msc@instxpos{#3},-\tmp@Ya)% \setlength{\tmp@Y}{\tmp@Ya}% \msc@drawtimer{stop}{\tmp@X}{\tmp@Y}{\msc@selfmesslabelpos}{}% }{ % else no second part needed }% }% }% } % % \msc@drawtimer draws the timer symbols % #1: type of the timer (set/timeout/stop) % #2: x-coordinate of center of timer % #3: y-coordinate of center of timer % #4: place text left (l) or right (r) % #5: text added to the timer \def\msc@drawtimer#1#2#3#4#5{% \setlength{\tmp@Xa}{#2-0.5\timerwidth}% \setlength{\tmp@Xb}{#2+0.5\timerwidth}% \ifthenelse{\equal{#1}{stop}}{% draw reset symbol \setlength{\tmp@Ya}{-#3+0.5\timerwidth}% \setlength{\tmp@Yb}{-#3-0.5\timerwidth}% \psline(\tmp@Xa,\tmp@Ya)(\tmp@Xb,\tmp@Yb)% \psline(\tmp@Xb,\tmp@Ya)(\tmp@Xa,\tmp@Yb)% }{% else draw set/timeout symbol \setlength{\tmp@Ya}{-#3+0.75\timerwidth}% \setlength{\tmp@Yb}{-#3-0.75\timerwidth}% \psline(\tmp@Xa,\tmp@Ya)(\tmp@Xb,\tmp@Yb)% (\tmp@Xa,\tmp@Yb)(\tmp@Xb,\tmp@Ya)(\tmp@Xa,\tmp@Ya)% }% \ifthenelse{\equal{#4}{l}}{% place label left \setlength{\tmp@Xa}{#2-\labeldist-0.3ex}% \setlength{\tmp@Ya}{-#3-0.5ex}% \rput[B](\tmp@Xa,\tmp@Ya){\makebox[0pt][r]{#5}} }{% else place label right \setlength{\tmp@Xa}{#2+\labeldist+0.3ex}% \setlength{\tmp@Ya}{-#3-0.5ex}% \rput[B](\tmp@Xa,\tmp@Ya){\makebox[0pt][l]{#5}}% }% } % % % \msc@drawinstancehead draws the head of the instance % #1: nickname of the instance % #2: text to put above the instance head symbol % #3: text to put inside the instance head symbol \def\msc@drawinstancehead#1#2#3{% \setlength{\tmp@X}{\msc@instxpos{#1}}% x-center head box \setlength{\tmp@Y}{\topheaddist+0.5\instheadheight}% y-center head box \setlength{\tmp@Xa}{-0.5\instwidth+\tmp@X}% x-upperleft head box \setlength{\tmp@Ya}{\topheaddist}% y-upperleft head box \setlength{\tmp@Xb}{\tmp@Xa+\instwidth}% x-lowerright head box \setlength{\tmp@Yb}{\topheaddist+\instheadheight}% y-lowerright head box \ifthenelse{\equal{\msc@insthead}{yes}}{% \psframe(\tmp@Xa,-\tmp@Ya)(\tmp@Xb,-\tmp@Yb)% }{% else, no head symbol drawing% } \rput[B](\tmp@X,-\tmp@Ya){\raisebox{\labeldist}{\makebox[0pt][c]{#2}}}% \rput[B](\tmp@X,-\tmp@Y){\raisebox{-.5ex}{\makebox[0pt][c]{#3}}}% } % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \def\msc@drawinstanceline#1{% \expandafter\@ifundefined{mscinst#1}{% \msc@instundefinederr{#1}}{% else, #1 is defined \ifthenelse{\equal{\msc@instypos{#1}}{undefined}}{% y-pos undefined: no line needed }{% else \setlength{\tmp@X}{\msc@instxpos{#1}}% \setlength{\tmp@Ya}{\msc@instypos{#1}}% \setlength{\tmp@Yb}{\msc@currentheight+\msc@headoffset}% \psline[linestyle=\msc@instlinestyle{#1}](\tmp@X,-\tmp@Ya)(\tmp@X,-\tmp@Yb)% }% }% } % % \msc@drawinstancefoot draws the last level and foot of the instance % #1: nickname of the instance \def\msc@drawinstancefoot#1{% \setlength{\tmp@Xa}{-0.5\instwidth+\msc@instxpos{#1}}% \setlength{\tmp@Ya}{\msc@currentheight+\msc@headoffset}% \setlength{\tmp@Xb}{\tmp@Xa+\instwidth}% \setlength{\tmp@Yb}{\msc@currentheight+\msc@headoffset+\instfootheight}% \ifthenelse{\equal{\msc@instfoot}{yes}}{ \psframe[fillstyle=solid,fillcolor=\msc@footcolor](\tmp@Xa,-\tmp@Ya)(\tmp@Xb,-\tmp@Yb)% }{% else, no foot symbol drawing% } } % % \nextlevel increases \msc@currentheight by #1 * \levelheight % (optional) #1: an integer number (defaults to 1) \newcommand{\nextlevel}[1][1]{% \addtolength{\msc@currentheight}{#1\levelheight}% } % \def\msc@drawinstancefooters{% \ifthenelse{\value{tmpcnt} < \value{mscinstcnt}}{% % Only draw the instancefoot if the instypos is defined (not ``undefined'') % This signals a previous instance stop. \ifthenelse{\equal{\msc@instypos{\msc@instnickname{tmpcnt}}}{undefined}}{\relax}{% \msc@drawinstanceline{\msc@instnickname{tmpcnt}}% \msc@drawinstancefoot{\msc@instnickname{tmpcnt}}% }% \stepcounter{tmpcnt}% \msc@drawinstancefooters}{% else nothing }}% % % \action puts an action symbol on the instance with nickname #2. % The action symbol will be placed on the current level and the text #1 % is centered inside the action symbol. \def\action#1#2{% \expandafter\@ifundefined{mscinst#2}{% \msc@instundefinederr{#2}}{% else, #2 is defined % first, draw the instance line as far as possible \msc@drawinstanceline{#2}% % then, draw the action symbol \setlength{\tmp@Xa}{\msc@instxpos{#2}-0.5\actionwidth}% \setlength{\tmp@Xb}{\tmp@Xa+\actionwidth}% \setlength{\tmp@Ya}{\msc@currentheight+\msc@headoffset}% \setlength{\tmp@Yb}{\tmp@Ya+\actionheight}% \psframe(\tmp@Xa,-\tmp@Ya)(\tmp@Xb,-\tmp@Yb)% \setlength{\tmp@X}{\msc@instxpos{#2}}% \setlength{\tmp@Y}{\tmp@Ya+0.5\actionheight}% \rput[B](\tmp@X,-\tmp@Y){\raisebox{-.5ex}{\makebox[0pt][c]{#1}}}% % redefine the instance's y position \setlength{\tmp@Y}{\msc@currentheight+\actionheight+\msc@headoffset}% \msc@setinstypos{#2}{\the\tmp@Y}% }% } % % \stop ends the instance with nickname #1. \def\stop#1{% \expandafter\@ifundefined{mscinst#1}{% \msc@instundefinederr{#1}}{% else, #1 is defined % first, draw the instance line as far as possible \msc@drawinstanceline{#1}% % then, draw the stop symbol \setlength{\tmp@X}{\msc@instxpos{#1}}% \setlength{\tmp@Ya}{\msc@instypos{#1}}% \setlength{\tmp@Yb}{\msc@currentheight+\msc@headoffset}% \setlength{\tmp@Xa}{\tmp@X-0.5\stopwidth}% \setlength{\tmp@Xb}{\tmp@X+0.5\stopwidth}% \setlength{\tmp@Ya}{\tmp@Yb+0.5\stopwidth}% \setlength{\tmp@Yb}{\tmp@Yb-0.5\stopwidth}% \psline(\tmp@Xa,-\tmp@Ya)(\tmp@Xb,-\tmp@Yb)% \psline(\tmp@Xb,-\tmp@Ya)(\tmp@Xa,-\tmp@Yb)% % redefine the instance's y position % ``undefined'' means that the instance axis will not be drawn any further \msc@setinstypos{#1}{undefined}% }% } % % % \condition puts a condition symbol over the given instances % #1: name to be put inside the condition symbol % #2: comma-separated list of instance nicknames, such that: % - The first instance nickname is supposed to be the leftmost % instance of the condition % - The last instance nickname is supposed to be the rightmost % instance of the condition \def\condition#1#2{% \def\msc@conditiontext{#1}% \def\msc@firstconditioninst{undefined}% \def\msc@lastconditioninst{undefined}% \msc@condition{#2}% % debugging info: % \message{(msc: condition: \msc@firstconditioninst...\msc@lastconditioninst)}% \setlength{\tmp@Xa}{\msc@instxpos{\msc@firstconditioninst}-\conditionoverlap}% \setlength{\tmp@Ya}{\msc@currentheight+\msc@headoffset}% \setlength{\tmp@Xb}{\msc@instxpos{\msc@lastconditioninst}+\conditionoverlap}% \setlength{\tmp@Yb}{\tmp@Ya+\conditionheight}% \msc@drawcondition{#1}{\tmp@Xa}{\tmp@Ya}{\tmp@Xb}{\tmp@Yb}% } % \def\msc@condition#1{% \@for\msccondition@rg:=#1\do{% \expandafter\@ifundefined{mscinst\msccondition@rg}{% \msc@instundefinederr{\msccondition@rg}}{% else, \msccondition@rg is defined % debugging info: % \message{(msc: condition instance "\msccondition@rg")}% \ifthenelse{\equal{\msc@firstconditioninst}{undefined}}{% \edef\msc@firstconditioninst{\msccondition@rg}% }{\ifthenelse{\lengthtest{\msc@instxpos{\msc@firstconditioninst} > \msc@instxpos{\msccondition@rg}}}{% \edef\msc@firstconditioninst{\msccondition@rg}}{}% }% \ifthenelse{\equal{\msc@lastconditioninst}{undefined}}{% \edef\msc@lastconditioninst{\msccondition@rg}% }{\ifthenelse{\lengthtest{\msc@instxpos{\msc@lastconditioninst} < \msc@instxpos{\msccondition@rg}}}{% \edef\msc@lastconditioninst{\msccondition@rg}}{}% } % now, draw the instance line as far as possible \setlength{\tmp@X}{\msc@instxpos{\msccondition@rg}}% \setlength{\tmp@Ya}{\msc@instypos{\msccondition@rg}}% \setlength{\tmp@Yb}{\msc@currentheight+\msc@headoffset}% \psline[linestyle=\msc@instlinestyle{\msccondition@rg}](\tmp@X,-\tmp@Ya)(\tmp@X,-\tmp@Yb)% % and redefine the instance's y position \setlength{\tmp@Y}{\msc@currentheight+\conditionheight+\msc@headoffset}% \msc@setinstypos{\msccondition@rg}{\the\tmp@Y}% }% }% } % % \msc@drawcondition draw the condition symbol % #1: condition-text \newlength{\tmp@tx}% \newlength{\tmp@ty}% \def\msc@drawcondition#1#2#3#4#5{% \setlength{\tmp@tx}{#4+ .6#5 - .6#3}% \setlength{\tmp@ty}{.5#3 + .5#5}% \psline(#2,-#3)(#4,-#3)(\tmp@tx,-\tmp@ty)(#4,-#5)% \setlength{\tmp@tx}{#2- .6#5 + .6#3}% \psline(#4,-#5)(#2,-#5)(\tmp@tx,-\tmp@ty)(#2,-#3)% \setlength{\tmp@tx}{.5#2 + .5#4}% \setlength{\tmp@ty}{.5#3 + .5#5}% \rput[B](\tmp@tx,-\tmp@ty){\raisebox{-.5ex}{\makebox[0pt][c]{#1}}}% } % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % GATES (Bill ?) % \gate[hpos][vpos]{text}{nickname} % \gate*[hpos][vpos]{text}{nickname} % (starred version puts a dot at the position of the gate on the instance line) % % hpos: optional horizontal position argument l(eft) or r(ight). default: l % vpos: optional vertical position argument t(op), c(enter) or b(ottom). default: t % text: text to be placed at the gate % nickname: nickname of the instance to which the gate belongs % \def\gate{\@ifstar{\def\msc@gatestar{defined}\msc@gateh}{\def\msc@gatestar{undefined}\msc@gateh}} \newcommand{\msc@gateh}[1][l]{% \def\msc@gatehpos{#1}% \msc@gatev% } % \newcommand{\msc@gatev}[3][t]{% \expandafter\@ifundefined{mscinst#3}{% \msc@instundefinederr{#3}}{% else, #3 is defined \ifthenelse{\equal{\msc@gatestar}{defined}}{% \setlength{\tmp@X}{\msc@instxpos{#3}}% \setlength{\tmp@Y}{\msc@currentheight + \msc@headoffset}% \pscircle[fillstyle=solid,fillcolor=black](\tmp@X,-\tmp@Y){.5mm}}{}% \ifthenelse{\equal{t}{#1}}{ \setlength{\tmp@Y}{\msc@currentheight + \msc@headoffset - \labeldist}% \def\msc@gatetext{{#2}}% }{% \ifthenelse{\equal{c}{#1}}{% \setlength{\tmp@Y}{\msc@currentheight + \msc@headoffset}% \def\msc@gatetext{\raisebox{-.5\totalheight}{#2}}% }{% \setlength{\tmp@Y}{\msc@currentheight + \msc@headoffset + \labeldist}% \def\msc@gatetext{\raisebox{-\totalheight}{#2}}% }}% \ifthenelse{\equal{l}{\msc@gatehpos}}{% \setlength{\tmp@X}{\msc@instxpos{#3} - \labeldist}% \rput[B](\tmp@X,-\tmp@Y){\makebox[0pt][r]{\msc@gatetext}}}{% \setlength{\tmp@X}{\msc@instxpos{#3} + \labeldist}% \rput[B](\tmp@X,-\tmp@Y){\makebox[0pt][l]{\msc@gatetext}}}% } } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % \drawmscframe draws a frame of the right size around the msc % This command also set the value of \msc@totalsizebox \def\msc@drawframe{% \global\msc@totalwidth =\msc@currentwidth% \setlength{\tmp@Y}{\msc@currentheight+\msc@headoffset+\instfootheight+\bottomfootdist}% \global\msc@totalheight =\tmp@Y% \ifthenelse{\equal{\msc@frame}{yes}}{% \psframe(0,0)(\msc@totalwidth,-\msc@totalheight)% }{% no frame drawing }% } % % \msckeyword is the keyword representation of msc \def\msckeyword{msc} \def\msckeywordstyle#1{\textbf{#1}} % % This keyword can be changed by the \setmckeyword command (or by \renewcommand{\msckeyword}{...}): \newcommand{\setmsckeyword}[1]{\def\msckeyword{#1}} \newcommand{\setmsckeywordstyle}[1]{\def\msckeywordstyle{#1}}% % % Commands to switch internal options that control the drawing of header and footer symbols \newcommand{\drawinsthead}[1]{\def\msc@insthead{#1}}% \drawinsthead{yes}% \newcommand{\drawinstfoot}[1]{\def\msc@instfoot{#1}}% \drawinstfoot{yes}% % A similar command to control drawing of the msc-frame \newcommand{\drawframe}[1]{\def\msc@frame{#1}}% \drawframe{yes}% % % \msc@settitle places #1 (the title) in the upperleft % corner of the msc frame \def\msc@settitle{% \rput[tl](0,-\topmscnamedist){% \makebox[\msc@totalwidth][\msc@titlejustification]{\hspace*{4pt}\msckeywordstyle{\msckeyword}{} \msc@title\hspace*{4pt}}% }% } % % \msc@title stores the title given in \begin{msc}{title} \def\msc@title{}% % % \msc@titlejustification says how the title should be justified % Justification is relative to the total width of the msc % l: left (default) % c: centered % r: right \def\msc@titlejustification{l} % \newsavebox{\mscbox}% % % the msc-environment \newenvironment{msc}[2][l]{% \message{( \msckeyword: "#2"}% \def\msc@titlejustification{#1}% \def\msc@title{#2}% \setcounter{mscinstcnt}{0}% \setlength{\msc@currentheight}{0pt}% \setlength{\msc@currentwidth}{0pt}% % define the artificial left and right environment instances \msc@declinst{envleft}{}{}% \msc@setinstxpos{envleft}{0pt}% \msc@declinst{envright}{}{}% \setlength{\tmp@X}{2\envinstdist}% \msc@setinstxpos{envright}{\the\tmp@X}% \begin{lrbox}{\mscbox} \begin{pspicture}(0,0)% we draw the msc in a picture of size 0x0 \psset{dash=4pt 4pt}% sets the hashed linestyle style }{% \addtolength{\msc@currentheight}{\lastlevelheight}% \setcounter{tmpcnt}{2}% \msc@drawinstancefooters% % If there is at least one instance, the current width is % set to the xpos of the NEXT msc instance. There is at least one instance, % if mscinstcnt >= 3. So, in that case, we have to % substract one \instdist from the current width. \ifthenelse{\value{mscinstcnt}<3}{% no user defined instances, so, add the \addtolength{\msc@currentwidth}{\envinstdist}% left (postponed) envinstdist to currentwidth }{% mscinstcnt >= 3 \addtolength{\msc@currentwidth}{-\instdist}% }% % Now we compute the final current width: one extra \envinstdist: \addtolength{\msc@currentwidth}{\envinstdist} \msc@drawframe% \msc@settitle% \end{pspicture}% % Debug info: %\typeout{msc size: \the\msc@totalwidth x\the\msc@totalheight}% \end{lrbox}% % the \mscbox now contains a box of 0x0, however the actual width and % height are stored in \msc@total{width,height}. We use these lengths % to adjust the width and height of the \mscbox \wd\mscbox=\msc@totalwidth% \ht\mscbox=\msc@totalheight% % Now the \mscbox can be scaled (by \mscscalefactor) and `printed': \scalebox{\mscscalefactor}{\raisebox{\msc@totalheight}[\msc@totalheight][0pt]{\usebox{\mscbox}}}% \message{)}% } % \def\mscunit{cm}% \def\setmscunit#1{\gdef\mscunit{#1}} % % \set@mscvalueslarge \def\set@mscvalueslarge{% \psset{linewidth=0.8pt} % the lengths \setlength{\topheaddist}{1.5\mscunit} \setlength{\bottomfootdist}{1\mscunit} \setlength{\instheadheight}{.6\mscunit} \setlength{\instfootheight}{0.25\mscunit} \setlength{\levelheight}{.75\mscunit} \setlength{\firstlevelheight}{0.75\mscunit} \setlength{\lastlevelheight}{0.5\mscunit} \setlength{\envinstdist}{2.5\mscunit} \setlength{\instdist}{3\mscunit} \setlength{\instwidth}{1.75\mscunit} \setlength{\topmscnamedist}{.2\mscunit} \setlength{\selfmesswidth}{.75\mscunit} \setlength{\labeldist}{1ex} \setlength{\coregionbarwidth}{.5\mscunit} \setlength{\lostsymbolradius}{.15\mscunit} \setlength{\stopwidth}{0.6\mscunit} \setlength{\timerwidth}{0.4\mscunit} \setlength{\actionheight}{0.75\mscunit} \setlength{\actionwidth}{1.25\mscunit} \setlength{\conditionheight}{0.75\mscunit} \setlength{\conditionoverlap}{0.6\mscunit} \setlength{\referenceoverlap}{1.5\mscunit} \setlength{\inlineoverlap}{1.5\mscunit} % some numeric parameters \messarrowscale{2} % foot color \setfootcolor{black} } % % % \set@mscvaluesnormal \def\set@mscvaluesnormal{% \psset{linewidth=0.7pt} % switch to a smaller font \small% % the lengths \setlength{\topheaddist}{1.3\mscunit} \setlength{\bottomfootdist}{0.7\mscunit} \setlength{\instheadheight}{.55\mscunit} \setlength{\instfootheight}{0.2\mscunit} \setlength{\levelheight}{.5\mscunit} \setlength{\firstlevelheight}{0.6\mscunit} \setlength{\lastlevelheight}{0.4\mscunit} \setlength{\envinstdist}{2\mscunit} \setlength{\instdist}{2.2\mscunit} \setlength{\instwidth}{1.6\mscunit} \setlength{\topmscnamedist}{.2\mscunit} \setlength{\selfmesswidth}{.6\mscunit} \setlength{\labeldist}{1ex} \setlength{\coregionbarwidth}{.4\mscunit} \setlength{\lostsymbolradius}{.12\mscunit} \setlength{\stopwidth}{0.5\mscunit} \setlength{\timerwidth}{0.3\mscunit} \setlength{\actionheight}{0.6\mscunit} \setlength{\actionwidth}{1.25\mscunit} \setlength{\conditionheight}{0.6\mscunit} \setlength{\conditionoverlap}{0.5\mscunit} \setlength{\referenceoverlap}{1\mscunit} \setlength{\inlineoverlap}{1\mscunit} % some numeric parameters \messarrowscale{1.5} % foot color \setfootcolor{black} } % % \set@mscvaluessmall \def\set@mscvaluessmall{% \psset{linewidth=0.6pt} % switch to a smaller font \small% % the lengths \setlength{\topheaddist}{1.2\mscunit} \setlength{\bottomfootdist}{0.5\mscunit} \setlength{\instheadheight}{0.5\mscunit} \setlength{\instfootheight}{0.15\mscunit} \setlength{\levelheight}{0.4\mscunit} \setlength{\firstlevelheight}{0.4\mscunit} \setlength{\lastlevelheight}{0.3\mscunit} \setlength{\envinstdist}{1.2\mscunit} \setlength{\instdist}{1.5\mscunit} \setlength{\instwidth}{1.2\mscunit} \setlength{\topmscnamedist}{.2\mscunit} \setlength{\selfmesswidth}{.4\mscunit} \setlength{\labeldist}{0.8ex} \setlength{\coregionbarwidth}{.2\mscunit} \setlength{\lostsymbolradius}{.08\mscunit} \setlength{\timerwidth}{0.2\mscunit} \setlength{\stopwidth}{0.3\mscunit} \setlength{\actionheight}{0.5\mscunit} \setlength{\actionwidth}{1.2\mscunit} \setlength{\conditionheight}{0.5\mscunit} \setlength{\conditionoverlap}{0.4\mscunit} \setlength{\referenceoverlap}{.75\mscunit} \setlength{\inlineoverlap}{.75\mscunit} % some numeric parameters \messarrowscale{1.2} % foot color \setfootcolor{black} } % % \setmscvalues assigns compatible values to all msc-parameters % Currently, three sets of values are supported: large, normal % and small. \def\setmscvalues#1{% \ifthenelse{\equal{#1}{large}}{% \set@mscvalueslarge}{% \ifthenelse{\equal{#1}{normal}}{% \set@mscvaluesnormal}{% \ifthenelse{\equal{#1}{small}}{% \set@mscvaluessmall}{% \msc@unknownmscvalueserr{#1}}}% }} % % initialisation of the msc-parameters \setmscvalues{normal} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Error and help messages % We use the standard LaTeX2e facilities to generate error and help % messages (for more info, see file lterror.dtx of LaTeX2e distribution). % % % nickname already defined \gdef\msc@nicknamedefinederr#1{% \PackageError{msc}{% error message nickname #1 already defined}{% help text You tried to use the nickname "#1" for a new\MessageBreak msc object (instance, reference, inline expression, etc.),\MessageBreak but the nickname is already assigned to another msc object.\MessageBreak press to continue (the new msc object will be ignored).}% } % % no such msc instance error \gdef\msc@instundefinederr#1{% \PackageError{msc}{% error message undefined msc instance: #1}{% help text You used "#1" as an msc instance nickname, but\MessageBreak there is no msc instance with that nickname.}% } % % unknown linestyle error \gdef\msc@unknownlinestyleerr#1{% \PackageError{msc}{% error message unknown linestyle: #1}{% help text Known msc linestyles are "solid", "dashed", and "dotted".\MessageBreak You used "#1".}% } % % unknown self message label position error \gdef\msc@unknownselfmesslabelposerr#1{% \PackageError{msc}{% error message unknown label position for self message: #1}{% help text Known label positions are "l" (left), "r" (right).\MessageBreak You used "#1".}% } % % unknown self message label position error \gdef\msc@unknownmscvalueserr#1{% \PackageError{msc}{% error message unknown set of msc-values: #1}{% help text Known sets of msc-values are "normal" and "small".\MessageBreak You used "#1".}% } % % no such msc reference error \gdef\msc@refundefinederr#1{% \PackageError{msc}{% error message undefined reference: #1}{% help text You used "#1" as a reference nickname, but\MessageBreak there is no reference with that nickname.}% } % % no such msc inline error \gdef\msc@inlundefinederr#1{% \PackageError{msc}{% error message undefined inline expression: #1}{% help text You used "#1" as a inline expression nickname, but\MessageBreak there is no inline expression with that nickname.}% } % % inline first right from last error \gdef\msc@inlfirstlasterror#1#2#3{% \PackageError{msc}{% error message first instance right from final instance\MessageBreak in inline expression #1}{% help text In the definition of inline expression "#1", you probably switched\MessageBreak the first msc instance, "#2", and the final msc instance, "#3",\MessageBreak since the first is located right from the final.}% } % % reference first rightt from last error \gdef\msc@reffirstlasterror#1#2#3{% \PackageError{msc}{% error message first instance right from final instance\MessageBreak in reference #1}{% help text In the definition of msc reference "#1", you probably switched\MessageBreak the first msc instance, "#2", and the final msc instance, "#3",\MessageBreak since the first is located right from the final.}% } % remarks % % Issuing pstricks drawing-commands inside a TeX-group in a pspicture environment % can result in ill-positioned objects. % % messages from/to the right environment should be defined after the last % instance is declared with \declinst