329 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			329 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | % Start of pgf-umlsd.sty | ||
|  | % | ||
|  | % Some macros for UML Sequence Diagrams. | ||
|  | % Home page of project: http://pgf-umlsd.googlecode.com/ | ||
|  | % Author: Xu Yuan <xuyuan.cn@gmail.com>, Southeast University, China | ||
|  | % Contributor: Nobel Huang <nobel1984@gmail.com>, Southeast University, China | ||
|  | % | ||
|  | % History: | ||
|  | % v0.7 2012/03/05 | ||
|  | %      - unify interface of call and callself | ||
|  | %      - non-instantaneous message | ||
|  | %      - bugfix: conflits with tikz library backgrounds | ||
|  | % v0.6 2011/07/27 | ||
|  | %      - Fix Issue 6 reported by frankmorgner@gmail.com | ||
|  | %        - diagram without a thread | ||
|  | %        - allows empty diagram | ||
|  | %      - New manual | ||
|  | % v0.5 2009/09/30 Fix Issue 2 reported by vlado.handziski | ||
|  | %      - Nested callself is supported | ||
|  | %      - Rename sdloop and sdframe to sdblock | ||
|  | % 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 <humbert@uni-wuppertal.de> 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/ | ||
|  | % | ||
|  | 
 | ||
|  | \NeedsTeXFormat{LaTeX2e}[1999/12/01] | ||
|  | \ProvidesPackage{pgf-umlsd}[2011/07/27 v0.6 Some LaTeX macros for UML | ||
|  | Sequence Diagrams.] | ||
|  | 
 | ||
|  | \RequirePackage{tikz} | ||
|  | \usetikzlibrary{arrows,shadows} | ||
|  | 
 | ||
|  | \RequirePackage{ifthen} | ||
|  | 
 | ||
|  | % 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 | ||
|  | 
 | ||
|  | % new counters | ||
|  | \newcounter{preinst} | ||
|  | \newcounter{instnum} | ||
|  | \newcounter{threadnum} | ||
|  | \newcounter{seqlevel} % level | ||
|  | \newcounter{callevel} | ||
|  | \newcounter{callselflevel} | ||
|  | \newcounter{blocklevel} | ||
|  | 
 | ||
|  | % 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}{umlsd@threadlayer} | ||
|  |     \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]{ | ||
|  | \ifthenelse{\equal{#2}{#4}} | ||
|  | { | ||
|  |   \begin{callself}[#1]{#2}{#3}{#5} | ||
|  | } | ||
|  | { | ||
|  |   \begin{callanother}[#1]{#2}{#3}{#4}{#5} | ||
|  | } | ||
|  | } | ||
|  | { | ||
|  | \ifthenelse{\equal{\f\thecallevel}{\t\thecallevel}} | ||
|  | { | ||
|  |   \end{callself} | ||
|  | } | ||
|  | { | ||
|  |   \end{callanother} | ||
|  | } | ||
|  | } | ||
|  | 
 | ||
|  | % function call to another instance | ||
|  | % interal use only | ||
|  | \newenvironment*{callanother}[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 | ||
|  | % interal use only | ||
|  | % Example: | ||
|  | % \begin{callself}[height]{caller}{function}{return} | ||
|  | % \end{callself} | ||
|  | \newenvironment*{callself}[4][1]{ | ||
|  |   \stepcounter{seqlevel} | ||
|  |   \stepcounter{callevel} % push | ||
|  |   \stepcounter{callselflevel} | ||
|  | 
 | ||
|  |   \path | ||
|  |   (#2)+(\thecallselflevel*0.1-0.1,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (sc\thecallevel) {} | ||
|  |   ({sc\thecallevel}.east)+(0,-0.33*\unitfactor) node (scb\thecallevel) {}; | ||
|  | 
 | ||
|  |   \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\t\thecallevel{#2} | ||
|  |   \def\returnvalue{#4} | ||
|  |   \tikzstyle{threadstyle}+=[instcolor#2] | ||
|  | }{ | ||
|  |   \addtocounter{seqlevel}{\l\thecallevel} | ||
|  |   \path (\f\thecallevel)+(\thecallselflevel*0.1-0.1,-\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 | ||
|  |   \addtocounter{callselflevel}{-1} | ||
|  | } | ||
|  | 
 | ||
|  | % message between threads | ||
|  | % Example: | ||
|  | % \mess[delay]{sender}{message content}{receiver} | ||
|  | \newcommand{\mess}[4][0]{ | ||
|  |   \stepcounter{seqlevel} | ||
|  |   \path | ||
|  |   (#2)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (mess from) {}; | ||
|  |   \addtocounter{seqlevel}{#1} | ||
|  |   \path | ||
|  |   (#4)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (mess to) {}; | ||
|  |   \draw[->,>=angle 60] (mess from) -- (mess to) node[midway, above] | ||
|  |   {#3}; | ||
|  | 
 | ||
|  |   \node (#3 from) at (mess from) {}; | ||
|  |   \node (#3 to) at (mess to) {}; | ||
|  | } | ||
|  | 
 | ||
|  | \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}} | ||
|  | 
 | ||
|  | % This function makes the call earlier. | ||
|  | \newcommand{\prelevel}{\addtocounter{seqlevel}{-1}} | ||
|  | 
 | ||
|  | % This function makes the call later. | ||
|  | \newcommand{\postlevel}{\addtocounter{seqlevel}{+1}} | ||
|  | 
 | ||
|  | % a block box with caption | ||
|  | % \begin{sdblock}[caption background color]{caption}{comments} | ||
|  | % \end{sdblock} | ||
|  | \newenvironment{sdblock}[3][white]{ | ||
|  |   \stepcounter{seqlevel} | ||
|  |   \stepcounter{blocklevel} % push | ||
|  |   \coordinate (blockbeg\theblocklevel) at (0,-\theseqlevel*\unitfactor-\unitfactor); | ||
|  |   \stepcounter{seqlevel} | ||
|  |   \def\blockcolor\theblocklevel{#1} | ||
|  |   \def\blockname\theblocklevel{#2} | ||
|  |   \def\blockcomm\theblocklevel{#3} | ||
|  |   \begin{pgfinterruptboundingbox} | ||
|  | }{ | ||
|  |   \coordinate (blockend) at (0,-\theseqlevel*\unitfactor-2*\unitfactor); | ||
|  |   \path (current bounding box.east)+(0.2,0) node (boxeast) {} | ||
|  |   (current bounding box.west |- {blockbeg\theblocklevel}) + (-0.2,0) | ||
|  |   node (nw) {}; | ||
|  |   \path (boxeast |- blockend) node (se) {}; | ||
|  | 
 | ||
|  |   % % title | ||
|  |   \node[blockstyle] (blocktitle) at (nw) {\blockname\theblocklevel}; | ||
|  |   \path (blocktitle.south east) + (0,0.2) node (set) {} | ||
|  |   (blocktitle.south east) + (-0.2,0) node (seb) {} | ||
|  |   (blocktitle.north east) + (0.2,0) node (comm) {}; | ||
|  |   \draw[fill=\blockcolor\theblocklevel] (blocktitle.north west) -- (blocktitle.north east) -- | ||
|  |   (set.center) -- (seb.center) -- (blocktitle.south west) -- cycle; | ||
|  |   \node[blockstyle] (blocktitle) at (nw) {\blockname\theblocklevel}; | ||
|  |   \node[blockcommentstyle] (blockcomment) at (comm) {\blockcomm\theblocklevel}; | ||
|  | 
 | ||
|  |   \coordinate (se) at (current bounding box.south east); | ||
|  |   \end{pgfinterruptboundingbox} | ||
|  | 
 | ||
|  |   \draw (se) rectangle (nw); | ||
|  | 
 | ||
|  |   \addtocounter{blocklevel}{-1} % pop | ||
|  |   \stepcounter{seqlevel} | ||
|  | } | ||
|  | 
 | ||
|  | % the environment of sequence diagram | ||
|  | \newenvironment{sequencediagram}{ | ||
|  |   % declare layers | ||
|  |   \pgfdeclarelayer{umlsd@background} | ||
|  |   \pgfdeclarelayer{umlsd@threadlayer} | ||
|  |   \pgfsetlayers{umlsd@background,umlsd@threadlayer,main} | ||
|  | 
 | ||
|  |   \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{blockstyle}=[anchor=north west] | ||
|  |     \tikzstyle{blockcommentstyle}=[anchor=north west, font=\small] | ||
|  |     \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{callselflevel}{0} | ||
|  |     \setcounter{blocklevel}{0} | ||
|  | 
 | ||
|  |     % origin | ||
|  |     \node[coordinate] (inst0) {}; | ||
|  | } | ||
|  | { | ||
|  |   \begin{pgfonlayer}{umlsd@background} | ||
|  |     \ifnum\c@instnum > 0 | ||
|  |     \foreach \t [evaluate=\t] in {1,...,\theinstnum}{ | ||
|  |       \draw[dotted] (inst\t) -- ++(0,-\theseqlevel*\unitfactor-2.2*\unitfactor); | ||
|  |     } | ||
|  |     \fi | ||
|  |     \ifnum\c@threadnum > 0 | ||
|  |     \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} | ||
|  |     } | ||
|  |     \fi | ||
|  |   \end{pgfonlayer} | ||
|  | \end{tikzpicture}} | ||
|  | 
 | ||
|  | 
 | ||
|  | %%% End of pgf-umlsd.sty | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |