%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Start of pgf-umlsd.sty % % Some macros for UML Sequence Diagrams. % Home page of project: http://pgf-umlsd.googlecode.com/ % Author: Xu Yuan , Southeast University, China % % History: % v0.4 2008/12/08 Fix Issue 1 reported by MathStuf: % Nested sdloop environment hides outer loop % v0.3 2008/11/10 in Berlin, fix for the PGF cvs version: % - the list items in \foreach are not evaluated by default now, % the `evaluate' opinion should be used % v0.2 2008/03/20 create project at http://pgf-umlsd.googlecode.com/ % - use `shadows' library % Thanks for Dr. Ludger Humbert's feedback! % - reduce the parameter numbers, the user can write the content % of instance (such as no colon) % - the user can redefine the `inststyle' % - new option: switch underlining of the instance text % - new option: switch rounded corners % v0.1 2008/01/25 first release at http://www.fauskes.net/pgftikzexamples/ % % Modified by Nobel Huang , Southeast University, China \NeedsTeXFormat{LaTeX2e}[1999/12/01] \ProvidesPackage{pgf-umlsd}[2008/03/20 v0.2 Some LaTeX macros for UML Sequence Diagrams.] % Options % ? the instance name under line ? \newif\ifpgfumlsdunderline\pgfumlsdunderlinetrue \DeclareOption{underline}{\pgfumlsdunderlinetrue} \DeclareOption{underline=true}{\pgfumlsdunderlinetrue} \DeclareOption{underline=false}{\pgfumlsdunderlinefalse} % ? the instance box with rounded corners ? \newif\ifpgfumlsdroundedcorners\pgfumlsdroundedcornersfalse \DeclareOption{roundedcorners}{\pgfumlsdroundedcornerstrue} \DeclareOption{roundedcorners=true}{\pgfumlsdroundedcornerstrue} \DeclareOption{roundedcorners=false}{\pgfumlsdroundedcornersfalse} \ProcessOptions % declare layers \pgfdeclarelayer{background} \pgfdeclarelayer{threadground} \pgfsetlayers{background,threadground,main} % new counters \newcounter{preinst} \newcounter{instnum} \newcounter{threadnum} \newcounter{seqlevel} % level \newcounter{callevel} \newcounter{looplevel} \newcounter{framelevel} % new an instance % Example: % \newinst[edge distance]{var}{name:class} \newcommand{\newinst}[3][0.2]{ \stepcounter{instnum} \path (inst\thepreinst.east)+(#1,0) node[inststyle] (inst\theinstnum) {\ifpgfumlsdunderline \underline{#3} \else #3 \fi}; \path (inst\theinstnum)+(0,-0.5*\unitfactor) node (#2) {}; \tikzstyle{instcolor#2}=[] \stepcounter{preinst} } % new an instance thread % Example: % \newinst[color]{var}{name}{class} \newcommand{\newthread}[3][gray!30]{ \newinst{#2}{#3} \stepcounter{threadnum} \node[below of=inst\theinstnum,node distance=0.8cm] (thread\thethreadnum) {}; \tikzstyle{threadcolor\thethreadnum}=[fill=#1] \tikzstyle{instcolor#2}=[fill=#1] } % draw running (thick) line, should not call directly \newcommand*{\drawthread}[2]{ \begin{pgfonlayer}{threadground} \draw[threadstyle] (#1.west) -- (#1.east) -- (#2.east) -- (#2.west) -- cycle; \end{pgfonlayer} } % a function call % Example: % \begin{call}[height]{caller}{function}{callee}{return} % \end{call} \newenvironment{call}[5][1]{ \stepcounter{seqlevel} \stepcounter{callevel} % push \path (#2)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (cf\thecallevel) {} (#4.\threadbias)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (ct\thecallevel) {}; \draw[->,>=triangle 60] ({cf\thecallevel}) -- (ct\thecallevel) node[midway, above] {#3}; \def\l\thecallevel{#1} \def\f\thecallevel{#2} \def\t\thecallevel{#4} \def\returnvalue{#5} \tikzstyle{threadstyle}+=[instcolor#2] } { \addtocounter{seqlevel}{\l\thecallevel} \path (\f\thecallevel)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (rf\thecallevel) {} (\t\thecallevel.\threadbias)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (rt\thecallevel) {}; \draw[dashed,->,>=angle 60] ({rt\thecallevel}) -- (rf\thecallevel) node[midway, above]{\returnvalue}; \drawthread{ct\thecallevel}{rt\thecallevel} \addtocounter{callevel}{-1} % pop } % a function do not need call others % Example: % \begin{callself}[height]{caller}{function}{return}{var} % \end{callself} \newenvironment{callself}[5][1]{ \stepcounter{seqlevel} \stepcounter{callevel} % push \path (#2)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (sc\thecallevel) {} ({sc\thecallevel}.east)+(0,-0.33*\unitfactor) node (scb\thecallevel) {}; \path ({#2}.east)+(0,0) node (#5) {}; \tikzstyle{instcolor#5}=[instcolor#2] \draw[->,>=triangle 60] ({sc\thecallevel}.east) -- ++(0.8,0) node[near start, above right] {#3} -- ++(0,-0.33*\unitfactor) -- (scb\thecallevel); \def\l\thecallevel{#1} \def\f\thecallevel{#2} \def\returnvalue{#4} \tikzstyle{threadstyle}+=[instcolor#2] }{ \addtocounter{seqlevel}{\l\thecallevel} \path (\f\thecallevel)+(0,-\theseqlevel*\unitfactor-0.33*\unitfactor) node (sct\thecallevel) {}; \draw[dashed,->,>=angle 60] ({sct\thecallevel}.east) node (sce\thecallevel) {} -- ++(0.8,0) -- node[midway, right]{\returnvalue} ++(0,-0.33*\unitfactor) -- ++(-0.8,0); \drawthread{scb\thecallevel}{sce\thecallevel} \addtocounter{callevel}{-1} % pop } % message between threads % Example: % \mess{sender}{message content}{receiver} \newcommand{\mess}[3]{ \stepcounter{seqlevel} \path (#1)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (messbeg) {} (#3)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (messend) {}; \draw[->,>=angle 60] (messbeg) -- (messend) node[midway, above] {#2}; } \newenvironment{messcall}[4][1]{ \stepcounter{seqlevel} \stepcounter{callevel} % push \path (#2)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (cf\thecallevel) {} (#4.\threadbias)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (ct\thecallevel) {}; \draw[->,>=angle 60] ({cf\thecallevel}) -- (ct\thecallevel) node[midway, above] {#3}; \def\l\thecallevel{#1} \def\f\thecallevel{#2} \def\t\thecallevel{#4} \tikzstyle{threadstyle}+=[instcolor#2] } { \addtocounter{seqlevel}{\l\thecallevel} \path (\f\thecallevel)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (rf\thecallevel) {} (\t\thecallevel.\threadbias)+(0,-\theseqlevel*\unitfactor-0.3*\unitfactor) node (rt\thecallevel) {}; \drawthread{ct\thecallevel}{rt\thecallevel} \addtocounter{callevel}{-1} % pop } % In the situation of multi-threads, some objects are called at the % same time. Currently, we have to adjust the bias of thread line % manually. Possible parameters are: center, west, east \newcommand{\setthreadbias}[1]{\global\def\threadbias{#1}} % In the situation of multi-threads, some events happen at the same % time. Currently, we have to adjust the level(time) of events % manually. This function makes the call earlier. \newcommand{\prelevel}{\addtocounter{seqlevel}{-1}} % a loop box with caption % \begin{sdloop}[caption background color]{caption} % \end{sdlopp} \newenvironment{sdloop}[2][white]{ \stepcounter{seqlevel} \stepcounter{looplevel} % push \coordinate (loopbeg\thelooplevel) at (0,-\theseqlevel*\unitfactor-\unitfactor); \stepcounter{seqlevel} \def\loopcolor\thelooplevel{#1} \def\loopname\thelooplevel{#2} \begin{pgfinterruptboundingbox} }{ \coordinate (loopend) at (0,-\theseqlevel*\unitfactor-2*\unitfactor); \path (current bounding box.east)+(0.2,0) node (boxeast) {} (current bounding box.west |- {loopbeg\thelooplevel}) + (-0.2,0) node (nw) {}; \path (boxeast |- loopend) node (se) {}; \draw (nw) rectangle (boxeast |- loopend); % title \node[loopstyle] (looptitle) at (nw) {\loopname\thelooplevel}; \path (looptitle.south east) + (0,0.2) node (set) {} (looptitle.south east) + (-0.2,0) node (seb) {}; \draw[fill=\loopcolor\thelooplevel] (looptitle.north west) -- (looptitle.north east) -- (set.center) -- (seb.center) -- (looptitle.south west) -- cycle; \node[loopstyle] (looptitle) at (nw) {\loopname\thelooplevel}; \end{pgfinterruptboundingbox} \node[dot] (fnw) at (nw) {}; \node[dot] (fse) at (se) {}; \addtocounter{looplevel}{-1} % pop \stepcounter{seqlevel} } \newenvironment{sdframe}[3][white]{ \stepcounter{seqlevel} \stepcounter{framelevel} \coordinate (framebeg\theframelevel) at (0,-\theseqlevel*\unitfactor-\unitfactor); \stepcounter{seqlevel} \def\framecolor\theframelevel{#1} \def\framename\theframelevel{#2} \def\framecons\theframelevel{#3} \begin{pgfinterruptboundingbox} }{ \coordinate (frameend) at (0,-\theseqlevel*\unitfactor-2*\unitfactor); \path (current bounding box.east)+(0.2,0) node (boxeast) {} (current bounding box.west |- {framebeg\theframelevel}) + (-0.2,0) node (nw) {}; \path (boxeast |- frameend) node (se) {}; \draw (nw) rectangle (se); % title \node[framestyle] (frametitle) at (nw) {\framename\theframelevel}; \path (frametitle.south east) + (0,0.2) node (set) {} (frametitle.south east) + (-0.2,0) node (seb) {}; \path (frametitle.north east) + (0.2,0) node (cons) {}; \draw[fill=\framecolor\theframelevel] (frametitle.north west) -- (frametitle.north east) -- (set.center) -- (seb.center) -- (frametitle.south west) -- cycle; \node[framestyle] (frametitle) at (nw) {\framename\theframelevel}; \node[frameconsstyle] (framecons) at (cons) {[\framecons\theframelevel]}; \end{pgfinterruptboundingbox} \node[dot] (fnw) at (nw) {}; \node[dot] (fse) at (se) {}; \addtocounter{framelevel}{-1} \stepcounter{seqlevel} } % the environment of sequence diagram \newenvironment{sequencediagram}{ \begin{tikzpicture} \setlength{\unitlength}{1cm} \tikzstyle{sequence}=[coordinate] \tikzstyle{inststyle}=[rectangle, draw, anchor=west, minimum height=0.8cm, minimum width=1.6cm, fill=white, drop shadow={opacity=1,fill=black}] \ifpgfumlsdroundedcorners \tikzstyle{inststyle}+=[rounded corners=3mm] \fi \tikzstyle{loopstyle}=[anchor=north west] \tikzstyle{framestyle}=[anchor=north west] \tikzstyle{frameconsstyle}=[anchor=north west] \tikzstyle{dot}=[inner sep=0pt,fill=black,circle,minimum size=0.2pt] \global\def\unitfactor{0.6} \global\def\threadbias{center} % reset counters \setcounter{preinst}{0} \setcounter{instnum}{0} \setcounter{threadnum}{0} \setcounter{seqlevel}{0} \setcounter{callevel}{0} \setcounter{looplevel}{0} \setcounter{framelevel}{0} % origin \node[coordinate] (inst0) {}; } { \begin{pgfonlayer}{background} \foreach \t [evaluate=\t] in {1,...,\theinstnum}{ \draw[dashed] (inst\t) -- ++(0,-\theseqlevel*\unitfactor-2.2*\unitfactor); } \foreach \t [evaluate=\t] in {1,...,\thethreadnum}{ \path (thread\t)+(0,-\theseqlevel*\unitfactor-0.1*\unitfactor) node (threadend) {}; \tikzstyle{threadstyle}+=[threadcolor\t] \drawthread{thread\t}{threadend} } \end{pgfonlayer} \end{tikzpicture}} %%% End of pgf-umlsd.sty %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%