| 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
|---|
| 2 | % Start of pgf-umlsd.sty |
|---|
| 3 | % |
|---|
| 4 | % Some macros for UML Sequence Diagrams. |
|---|
| 5 | % |
|---|
| 6 | % Author: Xu Yuan <xuyuan.cn@gmail.com>, Southeast University, China |
|---|
| 7 | % |
|---|
| 8 | % History: |
|---|
| 9 | % v0.2 2008/03/20 create project at http://pgf-umlsd.googlecode.com/ |
|---|
| 10 | % - use `shadows' library |
|---|
| 11 | % Thanks for Dr. Ludger Humbert's <humbert@uni-wuppertal.de> feedback! |
|---|
| 12 | % - reduce the parameter numbers, the user can write the content |
|---|
| 13 | % of instance (such as no colon) |
|---|
| 14 | % - the user can redefine the `inststyle' |
|---|
| 15 | % - new option: switch underlining of the instance text |
|---|
| 16 | % - new option: switch rounded corners |
|---|
| 17 | % v0.1 2008/01/25 first release at http://www.fauskes.net/pgftikzexamples/ |
|---|
| 18 | |
|---|
| 19 | \NeedsTeXFormat{LaTeX2e}[1999/12/01] |
|---|
| 20 | \ProvidesPackage{pgf-umlsd}[2008/03/20 v0.2 Some LaTeX macros for UML |
|---|
| 21 | Sequence Diagrams.] |
|---|
| 22 | |
|---|
| 23 | % Options |
|---|
| 24 | % ? the instance name under line ? |
|---|
| 25 | \newif\ifpgfumlsdunderline\pgfumlsdunderlinetrue |
|---|
| 26 | \DeclareOption{underline}{\pgfumlsdunderlinetrue} |
|---|
| 27 | \DeclareOption{underline=true}{\pgfumlsdunderlinetrue} |
|---|
| 28 | \DeclareOption{underline=false}{\pgfumlsdunderlinefalse} |
|---|
| 29 | % ? the instance box with rounded corners ? |
|---|
| 30 | \newif\ifpgfumlsdroundedcorners\pgfumlsdroundedcornersfalse |
|---|
| 31 | \DeclareOption{roundedcorners}{\pgfumlsdroundedcornerstrue} |
|---|
| 32 | \DeclareOption{roundedcorners=true}{\pgfumlsdroundedcornerstrue} |
|---|
| 33 | \DeclareOption{roundedcorners=false}{\pgfumlsdroundedcornersfalse} |
|---|
| 34 | \ProcessOptions |
|---|
| 35 | |
|---|
| 36 | % declare layers |
|---|
| 37 | \pgfdeclarelayer{background} |
|---|
| 38 | \pgfdeclarelayer{threadground} |
|---|
| 39 | \pgfsetlayers{background,threadground,main} |
|---|
| 40 | |
|---|
| 41 | % new counters |
|---|
| 42 | \newcounter{preinst} |
|---|
| 43 | \newcounter{instnum} |
|---|
| 44 | \newcounter{threadnum} |
|---|
| 45 | \newcounter{seqlevel} % level |
|---|
| 46 | \newcounter{callevel} |
|---|
| 47 | \newcounter{looplevel} |
|---|
| 48 | |
|---|
| 49 | % new an instance |
|---|
| 50 | % Example: |
|---|
| 51 | % \newinst[edge distance]{var}{name:class} |
|---|
| 52 | \newcommand{\newinst}[3][0.2]{ |
|---|
| 53 | \stepcounter{instnum} |
|---|
| 54 | \path (inst\thepreinst.east)+(#1,0) node[inststyle] (inst\theinstnum) |
|---|
| 55 | {\ifpgfumlsdunderline |
|---|
| 56 | \underline{#3} |
|---|
| 57 | \else |
|---|
| 58 | #3 |
|---|
| 59 | \fi}; |
|---|
| 60 | \path (inst\theinstnum)+(0,-0.5*\unitfactor) node (#2) {}; |
|---|
| 61 | \tikzstyle{instcolor#2}=[] |
|---|
| 62 | \stepcounter{preinst} |
|---|
| 63 | } |
|---|
| 64 | |
|---|
| 65 | % new an instance thread |
|---|
| 66 | % Example: |
|---|
| 67 | % \newinst[color]{var}{name}{class} |
|---|
| 68 | \newcommand{\newthread}[3][gray!30]{ |
|---|
| 69 | \newinst{#2}{#3} |
|---|
| 70 | \stepcounter{threadnum} |
|---|
| 71 | \node[below of=inst\theinstnum,node distance=0.8cm] (thread\thethreadnum) {}; |
|---|
| 72 | \tikzstyle{threadcolor\thethreadnum}=[fill=#1] |
|---|
| 73 | \tikzstyle{instcolor#2}=[fill=#1] |
|---|
| 74 | } |
|---|
| 75 | |
|---|
| 76 | % draw running (thick) line, should not call directly |
|---|
| 77 | \newcommand*{\drawthread}[2]{ |
|---|
| 78 | \begin{pgfonlayer}{threadground} |
|---|
| 79 | \draw[threadstyle] (#1.west) -- (#1.east) -- (#2.east) -- (#2.west) -- cycle; |
|---|
| 80 | \end{pgfonlayer} |
|---|
| 81 | } |
|---|
| 82 | |
|---|
| 83 | % a function call |
|---|
| 84 | % Example: |
|---|
| 85 | % \begin{call}[height]{caller}{function}{callee}{return} |
|---|
| 86 | % \end{call} |
|---|
| 87 | \newenvironment{call}[5][1]{ |
|---|
| 88 | \stepcounter{seqlevel} |
|---|
| 89 | \stepcounter{callevel} % push |
|---|
| 90 | \path |
|---|
| 91 | (#2)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (cf\thecallevel) {} |
|---|
| 92 | (#4.\threadbias)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (ct\thecallevel) {}; |
|---|
| 93 | |
|---|
| 94 | \draw[->,>=triangle 60] ({cf\thecallevel}) -- (ct\thecallevel) |
|---|
| 95 | node[midway, above] {\small #3}; |
|---|
| 96 | \def\l\thecallevel{#1} |
|---|
| 97 | \def\f\thecallevel{#2} |
|---|
| 98 | \def\t\thecallevel{#4} |
|---|
| 99 | \def\returnvalue{#5} |
|---|
| 100 | \tikzstyle{threadstyle}+=[instcolor#2] |
|---|
| 101 | } |
|---|
| 102 | { |
|---|
| 103 | \addtocounter{seqlevel}{\l\thecallevel} |
|---|
| 104 | \path |
|---|
| 105 | (\f\thecallevel)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (rf\thecallevel) {} |
|---|
| 106 | (\t\thecallevel.\threadbias)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (rt\thecallevel) {}; |
|---|
| 107 | \draw[dashed,->,>=angle 60] ({rt\thecallevel}) -- (rf\thecallevel) |
|---|
| 108 | node[midway, above]{\small \returnvalue}; |
|---|
| 109 | \drawthread{ct\thecallevel}{rt\thecallevel} |
|---|
| 110 | \addtocounter{callevel}{-1} % pop |
|---|
| 111 | } |
|---|
| 112 | |
|---|
| 113 | % a function do not need call others |
|---|
| 114 | % Example: |
|---|
| 115 | % \begin{callself}[height]{caller}{function}{return} |
|---|
| 116 | % \end{callself} |
|---|
| 117 | \newenvironment{callself}[4][1]{ |
|---|
| 118 | \stepcounter{seqlevel} |
|---|
| 119 | \stepcounter{callevel} % push |
|---|
| 120 | \path |
|---|
| 121 | (#2)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (sc\thecallevel) {} |
|---|
| 122 | ({sc\thecallevel}.east)+(0,-0.33*\unitfactor) node (scb\thecallevel) {}; |
|---|
| 123 | |
|---|
| 124 | \draw[->,>=triangle 60] ({sc\thecallevel}.east) -- ++(0.8,0) |
|---|
| 125 | node[near start, above right] {\small #3} -- ++(0,-0.33*\unitfactor) |
|---|
| 126 | -- (scb\thecallevel); |
|---|
| 127 | \def\l\thecallevel{#1} |
|---|
| 128 | \def\f\thecallevel{#2} |
|---|
| 129 | \def\returnvalue{#4} |
|---|
| 130 | \tikzstyle{threadstyle}+=[instcolor#2] |
|---|
| 131 | }{ |
|---|
| 132 | \addtocounter{seqlevel}{\l\thecallevel} |
|---|
| 133 | \path (\f\thecallevel)+(0,-\theseqlevel*\unitfactor-0.33*\unitfactor) node |
|---|
| 134 | (sct\thecallevel) {}; |
|---|
| 135 | |
|---|
| 136 | \draw[dashed,->,>=angle 60] ({sct\thecallevel}.east) node |
|---|
| 137 | (sce\thecallevel) {} -- ++(0.8,0) -- node[midway, right]{\small \returnvalue} ++(0,-0.33*\unitfactor) -- ++(-0.8,0); |
|---|
| 138 | \drawthread{scb\thecallevel}{sce\thecallevel} |
|---|
| 139 | \addtocounter{callevel}{-1} % pop |
|---|
| 140 | } |
|---|
| 141 | |
|---|
| 142 | % message between threads |
|---|
| 143 | % Example: |
|---|
| 144 | % \mess{sender}{message content}{receiver} |
|---|
| 145 | \newcommand{\mess}[3]{ |
|---|
| 146 | \stepcounter{seqlevel} |
|---|
| 147 | \path |
|---|
| 148 | (#1)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (messbeg) {} |
|---|
| 149 | (#3)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (messend) {}; |
|---|
| 150 | \draw[->,>=angle 60] (messbeg) -- (messend) node[midway, above] {\small #2}; |
|---|
| 151 | } |
|---|
| 152 | |
|---|
| 153 | % In the situation of multi-threads, some objects are called at the |
|---|
| 154 | % same time. Currently, we have to adjust the bias of thread line |
|---|
| 155 | % manually. Possible parameters are: center, west, east |
|---|
| 156 | \newcommand{\setthreadbias}[1]{\global\def\threadbias{#1}} |
|---|
| 157 | |
|---|
| 158 | % In the situation of multi-threads, some events happen at the same |
|---|
| 159 | % time. Currently, we have to adjust the level(time) of events |
|---|
| 160 | % manually. This function makes the call eariler. |
|---|
| 161 | \newcommand{\prelevel}{\addtocounter{seqlevel}{-1}} |
|---|
| 162 | |
|---|
| 163 | % a loop box with caption |
|---|
| 164 | % \begin{sdloop}[caption background color]{caption} |
|---|
| 165 | % \end{sdlopp} |
|---|
| 166 | \newenvironment{sdloop}[2][white]{ |
|---|
| 167 | \stepcounter{seqlevel} |
|---|
| 168 | \stepcounter{looplevel} % push |
|---|
| 169 | \coordinate (loopbeg\thelooplevel) at (0,-\theseqlevel*\unitfactor-0.5*\unitfactor); |
|---|
| 170 | \def\loopcolor\thelooplevel{#1} |
|---|
| 171 | \def\loopname\thelooplevel{#2} |
|---|
| 172 | \begin{pgfinterruptboundingbox} |
|---|
| 173 | }{ |
|---|
| 174 | \coordinate (loopend) at (0,-\theseqlevel*\unitfactor-1.4*\unitfactor); |
|---|
| 175 | \path (current bounding box.east)+(0.2,0) node (boxeast) {} |
|---|
| 176 | (current bounding box.west |- {loopbeg\thelooplevel}) + (-0.2,0) |
|---|
| 177 | node (nw) {}; |
|---|
| 178 | \draw (nw) rectangle (boxeast |- loopend); %se |
|---|
| 179 | |
|---|
| 180 | % title |
|---|
| 181 | \node[loopstyle] (looptitle) at (nw) {\loopname\thelooplevel}; |
|---|
| 182 | \path (looptitle.south east) + (0,0.2) node (set) {} |
|---|
| 183 | (looptitle.south east) + (-0.2,0) node (seb) {}; |
|---|
| 184 | \draw[fill=\loopcolor\thelooplevel] (looptitle.north west) -- (looptitle.north east) -- |
|---|
| 185 | (set.center) -- (seb.center) -- (looptitle.south west) -- cycle; |
|---|
| 186 | \node[loopstyle] (looptitle) at (nw) {\loopname\thelooplevel}; |
|---|
| 187 | |
|---|
| 188 | \end{pgfinterruptboundingbox} |
|---|
| 189 | \addtocounter{looplevel}{-1} % pop |
|---|
| 190 | } |
|---|
| 191 | |
|---|
| 192 | % the environment of sequence diagram |
|---|
| 193 | \newenvironment{sequencediagram}{ |
|---|
| 194 | \begin{tikzpicture} |
|---|
| 195 | \setlength{\unitlength}{1cm} |
|---|
| 196 | \tikzstyle{sequence}=[coordinate] |
|---|
| 197 | \tikzstyle{inststyle}=[rectangle, draw, anchor=west, minimum |
|---|
| 198 | height=0.8cm, minimum width=1.6cm, fill=white, |
|---|
| 199 | drop shadow={opacity=1,fill=black}] |
|---|
| 200 | \ifpgfumlsdroundedcorners |
|---|
| 201 | \tikzstyle{inststyle}+=[rounded corners=3mm] |
|---|
| 202 | \fi |
|---|
| 203 | \tikzstyle{loopstyle}=[anchor=north west] |
|---|
| 204 | \global\def\unitfactor{0.6} |
|---|
| 205 | \global\def\threadbias{center} |
|---|
| 206 | % reset counters |
|---|
| 207 | \setcounter{preinst}{0} |
|---|
| 208 | \setcounter{instnum}{0} |
|---|
| 209 | \setcounter{threadnum}{0} |
|---|
| 210 | \setcounter{seqlevel}{0} |
|---|
| 211 | \setcounter{callevel}{0} |
|---|
| 212 | \setcounter{looplevel}{0} |
|---|
| 213 | |
|---|
| 214 | % origin |
|---|
| 215 | \node[coordinate] (inst0) {}; |
|---|
| 216 | } |
|---|
| 217 | { |
|---|
| 218 | \begin{pgfonlayer}{background} |
|---|
| 219 | \foreach \t in {1,...,\theinstnum}{ |
|---|
| 220 | \draw[dotted] (inst\t) -- ++(0,-\theseqlevel*\unitfactor-2.2*\unitfactor); |
|---|
| 221 | } |
|---|
| 222 | \foreach \t in {1,...,\thethreadnum}{ |
|---|
| 223 | \path (thread\t)+(0,-\theseqlevel*\unitfactor-0.1*\unitfactor) node (threadend) {}; |
|---|
| 224 | \tikzstyle{threadstyle}+=[threadcolor\t] |
|---|
| 225 | \drawthread{thread\t}{threadend} |
|---|
| 226 | } |
|---|
| 227 | \end{pgfonlayer} |
|---|
| 228 | \end{tikzpicture}} |
|---|
| 229 | |
|---|
| 230 | |
|---|
| 231 | %%% End of pgf-umlsd.sty |
|---|
| 232 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
|---|