From d243892ad9717d0d1cbb0dbc941b229b24a7f09e Mon Sep 17 00:00:00 2001 From: Glenn Hutchings Date: Thu, 14 Apr 2016 20:38:24 +0100 Subject: [PATCH] Use blockdiag to create the Heidi box diagrams. --- README.md | 27 +++- chapters/04.rst | 72 +++++---- conf.py | 32 +++- figures/heidiobj1.diag | 23 +++ figures/heidiobj2.diag | 23 +++ figures/heidiobj3.diag | 23 +++ figures/heidiobj4.diag | 24 +++ figures/heidiobj5.diag | 24 +++ figures/heidiobj6.diag | 24 +++ figures/heidiobj7.diag | 24 +++ figures/heidiobj8.diag | 24 +++ images/heidiobj1.png | Bin 2136 -> 0 bytes images/heidiobj2.png | Bin 2272 -> 0 bytes images/heidiobj3.png | Bin 2355 -> 0 bytes images/heidiobj4.png | Bin 2384 -> 0 bytes images/heidiobj5.png | Bin 2387 -> 0 bytes images/heidiobj6.png | Bin 2559 -> 0 bytes images/heidiobj7.png | Bin 2519 -> 0 bytes images/heidiobj8.png | Bin 2484 -> 0 bytes tools/__init__.py | 0 tools/blockdiag.py | 334 +++++++++++++++++++++++++++++++++++++++++ 21 files changed, 614 insertions(+), 40 deletions(-) create mode 100644 figures/heidiobj1.diag create mode 100644 figures/heidiobj2.diag create mode 100644 figures/heidiobj3.diag create mode 100644 figures/heidiobj4.diag create mode 100644 figures/heidiobj5.diag create mode 100644 figures/heidiobj6.diag create mode 100644 figures/heidiobj7.diag create mode 100644 figures/heidiobj8.diag delete mode 100644 images/heidiobj1.png delete mode 100644 images/heidiobj2.png delete mode 100644 images/heidiobj3.png delete mode 100644 images/heidiobj4.png delete mode 100644 images/heidiobj5.png delete mode 100644 images/heidiobj6.png delete mode 100644 images/heidiobj7.png delete mode 100644 images/heidiobj8.png create mode 100644 tools/__init__.py create mode 100644 tools/blockdiag.py diff --git a/README.md b/README.md index e90ea93..eb05a28 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,14 @@ Introduction This repository contains the sources for the [Inform Beginner's Guide](http://www.firthworks.com/roger/IBG.html), henceforth known as the IBG. This version is in a new source format that's -more contributor-friendly (see below). It's a work-in-progress; see the -[issue tracker](https://github.com/i6/ibg/issues) for how it's going. +more version-control and contributor-friendly: +[Sphinx](http://sphinx-doc.org), a documentation build tool written in +[Python](http://python.org). With Sphinx, the source files are in a very +readable format called +[reStructuredText](https://en.wikipedia.org/wiki/ReStructuredText). +This version of the IBG is a work-in-progress; see the +[issue tracker](https://github.com/i6/ibg/issues) for how it's going. Initially it will be a straight conversion of the 3rd edition. After that, the 4th edition will be prepared. The rationale for a 4th edition is: @@ -25,13 +30,19 @@ the 4th edition will be prepared. The rationale for a 4th edition is: Building from source -------------------- -The new source format is [Sphinx](http://sphinx-doc.org), a documentation -build tool written in [Python](http://python.org), which you will need to -install if you want to build the document. You can find the complete -installation instructions -[here](http://www.sphinx-doc.org/en/stable/install.html). +As well as these document sources, you will need: + +* Sphinx. You can find the complete installation instructions + [here](http://www.sphinx-doc.org/en/stable/install.html). + +* Sphinx makes use of [Blockdiag](https://pypi.python.org/pypi/blockdiag) + for some of the diagrams; you'll need that too. + +If you have `pip`, this command will be all you need: + + pip install sphinx blockdiag -After you have Sphinx installed, you can build the HTML version of the +After you have everything installed, you can build the HTML version of the guide from a command prompt, like this: make html diff --git a/chapters/04.rst b/chapters/04.rst index 8c6a7ed..d9949bb 100644 --- a/chapters/04.rst +++ b/chapters/04.rst @@ -284,45 +284,57 @@ This causes another change in the relationships. The bird is now a child of the player (and *not* of the forest), and the player is both a parent (of the bird) and a child (of the forest). -In this diagram, we show how the object relationships change during the -course of the game. The straight lines represent parent--child -relationships, with the parent object at the top of the line, and the child -object at the bottom. +Here we show how the object relationships change during the course of the +game. The straight lines represent parent--child relationships, with the +parent object at the top of the line, and the child object at the bottom. -.. list-table:: - :widths: 1 3 5 +1. At the start of the game: - * - 1. - - At the start of the game: - - .. image:: /images/heidiobj1.* + .. blockdiag:: /figures/heidiobj1.diag + :align: center + :scale: 80% - * - 2. - - The player types: ``GO EAST`` - - .. image:: /images/heidiobj2.* +2. The player types: ``GO EAST`` - * - 3. - - The player types: ``TAKE THE BIRD`` - - .. image:: /images/heidiobj3.* + .. blockdiag:: /figures/heidiobj2.diag + :align: center + :scale: 80% - * - 4. - - The player types: ``GO NORTHEAST`` - - .. image:: /images/heidiobj4.* +3. The player types: ``TAKE THE BIRD`` - * - 5. - - The player types: ``PUT BIRD IN NEST`` - - .. image:: /images/heidiobj5.* + .. blockdiag:: /figures/heidiobj3.diag + :align: center + :scale: 80% - * - 6. - - The player types: ``TAKE NEST`` - - .. image:: /images/heidiobj6.* +4. The player types: ``GO NORTHEAST`` - * - 7. - - The player types: ``UP`` - - .. image:: /images/heidiobj7.* + .. blockdiag:: /figures/heidiobj4.diag + :align: center + :scale: 80% - * - 8. - - The player types: ``PUT NEST ON BRANCH`` - - .. image:: /images/heidiobj8.* +5. The player types: ``PUT BIRD IN NEST`` + + .. blockdiag:: /figures/heidiobj5.diag + :align: center + :scale: 80% + +6. The player types: ``TAKE NEST`` + + .. blockdiag:: /figures/heidiobj6.diag + :align: center + :scale: 80% + +7. The player types: ``UP`` + + .. blockdiag:: /figures/heidiobj7.diag + :align: center + :scale: 80% + +8. The player types: ``PUT NEST ON BRANCH`` + + .. blockdiag:: /figures/heidiobj8.diag + :align: center + :scale: 80% In this short example, we've taken a lot of time and space to spell out exactly how the objects relationship patterns -- generally known as the diff --git a/conf.py b/conf.py index 402eb1c..7546c75 100644 --- a/conf.py +++ b/conf.py @@ -20,9 +20,9 @@ import codecs # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -sys.path.insert(0, os.path.abspath('tools')) +sys.path.insert(0, ".") -from transcript import TranscriptLexer +from tools.transcript import TranscriptLexer # Setup function. def setup(app): @@ -38,6 +38,7 @@ def setup(app): # ones. extensions = [ 'sphinx.ext.todo', + 'tools.blockdiag', ] # Add any paths that contain templates here, relative to this directory. @@ -331,3 +332,30 @@ texinfo_documents = [ # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False + + +# -- Options for block diagrams ------------------------------------------- + +# The paths to truetype fonts. blockdiag_fontpath option accepts both +# single path string and list of paths. +blockdiag_fontpath = [] + +# The path to fontmap definitions. +blockdiag_fontmap = "" + +# Render diagrams in antialias mode or not. +blockdiag_antialias = True + +# Render diagrams as transparency or not. +blockdiag_transparency = True + +# The output image format at generating HTML docs ("PNG" or "SVG"). +blockdiag_html_image_format = "SVG" + +# The output image format at generating PDF docs (through LaTeX). ("PNG" or +# "PDF"). When a value of PDF is specified, you can get clear diagram +# images. In which case, reportlab library is required. +blockdiag_latex_image_format = "PNG" + +# Enable debug mode of blockdiag. +blockdiag_debug = False diff --git a/figures/heidiobj1.diag b/figures/heidiobj1.diag new file mode 100644 index 0000000..3e18718 --- /dev/null +++ b/figures/heidiobj1.diag @@ -0,0 +1,23 @@ +// 1. At the start of the game + +blockdiag { + default_shape = roundedbox; + orientation = portrait; + node_width = 80; + + BC [label = "before_\ncottage"]; + F [label = "forest"]; + C [label = "clearing"]; + TT [label = "top_of_\ntree"]; + + P [label = "player"]; + B [label = "bird"]; + N [label = "nest"]; + T [label = "tree"]; + TB [label = "branch"]; + + BC -> P; + F -> B; + C -> N, T; + TT -> TB; +} diff --git a/figures/heidiobj2.diag b/figures/heidiobj2.diag new file mode 100644 index 0000000..8564db5 --- /dev/null +++ b/figures/heidiobj2.diag @@ -0,0 +1,23 @@ +// 2. The player types: ``GO EAST`` + +blockdiag { + default_shape = roundedbox; + orientation = portrait; + node_width = 80; + + BC [label = "before_\ncottage"]; + F [label = "forest"]; + C [label = "clearing"]; + TT [label = "top_of_\ntree"]; + + P [label = "player"]; + B [label = "bird"]; + N [label = "nest"]; + T [label = "tree"]; + TB [label = "branch"]; + + BC; + F -> P, B; + C -> N, T; + TT -> TB; +} diff --git a/figures/heidiobj3.diag b/figures/heidiobj3.diag new file mode 100644 index 0000000..c7c41f9 --- /dev/null +++ b/figures/heidiobj3.diag @@ -0,0 +1,23 @@ +// 3. The player types: ``TAKE THE BIRD`` + +blockdiag { + default_shape = roundedbox; + orientation = portrait; + node_width = 80; + + BC [label = "before_\ncottage"]; + F [label = "forest"]; + C [label = "clearing"]; + TT [label = "top_of_\ntree"]; + + P [label = "player"]; + B [label = "bird"]; + N [label = "nest"]; + T [label = "tree"]; + TB [label = "branch"]; + + BC; + F -> P -> B; + C -> N, T; + TT -> TB; +} diff --git a/figures/heidiobj4.diag b/figures/heidiobj4.diag new file mode 100644 index 0000000..a4dbdf8 --- /dev/null +++ b/figures/heidiobj4.diag @@ -0,0 +1,24 @@ +// 4. The player types: ``GO NORTHEAST`` + +blockdiag { + default_shape = roundedbox; + orientation = portrait; + node_width = 80; + + BC [label = "before_\ncottage"]; + F [label = "forest"]; + C [label = "clearing"]; + TT [label = "top_of_\ntree"]; + + P [label = "player"]; + B [label = "bird"]; + N [label = "nest"]; + T [label = "tree"]; + TB [label = "branch"]; + + BC; + F; + C -> P -> B; + C -> N, T; + TT -> TB; +} diff --git a/figures/heidiobj5.diag b/figures/heidiobj5.diag new file mode 100644 index 0000000..c6be0d8 --- /dev/null +++ b/figures/heidiobj5.diag @@ -0,0 +1,24 @@ +// 5. The player types: ``PUT BIRD IN NEST`` + +blockdiag { + default_shape = roundedbox; + orientation = portrait; + node_width = 80; + + BC [label = "before_\ncottage"]; + F [label = "forest"]; + C [label = "clearing"]; + TT [label = "top_of_\ntree"]; + + P [label = "player"]; + B [label = "bird"]; + N [label = "nest"]; + T [label = "tree"]; + TB [label = "branch"]; + + BC; + F; + C -> N -> B; + C -> P, T; + TT -> TB; +} diff --git a/figures/heidiobj6.diag b/figures/heidiobj6.diag new file mode 100644 index 0000000..a1d915a --- /dev/null +++ b/figures/heidiobj6.diag @@ -0,0 +1,24 @@ +// 6. The player types: ``TAKE NEST`` + +blockdiag { + default_shape = roundedbox; + orientation = portrait; + node_width = 80; + + BC [label = "before_\ncottage"]; + F [label = "forest"]; + C [label = "clearing"]; + TT [label = "top_of_\ntree"]; + + P [label = "player"]; + B [label = "bird"]; + N [label = "nest"]; + T [label = "tree"]; + TB [label = "branch"]; + + BC; + F; + C -> P -> N -> B; + C -> T; + TT -> TB; +} diff --git a/figures/heidiobj7.diag b/figures/heidiobj7.diag new file mode 100644 index 0000000..74628f0 --- /dev/null +++ b/figures/heidiobj7.diag @@ -0,0 +1,24 @@ +// 7. The player types: ``UP`` + +blockdiag { + default_shape = roundedbox; + orientation = portrait; + node_width = 80; + + BC [label = "before_\ncottage"]; + F [label = "forest"]; + C [label = "clearing"]; + TT [label = "top_of_\ntree"]; + + P [label = "player"]; + B [label = "bird"]; + N [label = "nest"]; + T [label = "tree"]; + TB [label = "branch"]; + + BC; + F; + C -> T; + TT -> P -> N -> B; + TT -> TB; +} diff --git a/figures/heidiobj8.diag b/figures/heidiobj8.diag new file mode 100644 index 0000000..edd792b --- /dev/null +++ b/figures/heidiobj8.diag @@ -0,0 +1,24 @@ +// 8. The player types: ``PUT NEST ON BRANCH`` + +blockdiag { + default_shape = roundedbox; + orientation = portrait; + node_width = 80; + + BC [label = "before_\ncottage"]; + F [label = "forest"]; + C [label = "clearing"]; + TT [label = "top_of_\ntree"]; + + P [label = "player"]; + B [label = "bird"]; + N [label = "nest"]; + T [label = "tree"]; + TB [label = "branch"]; + + BC; + F; + C -> T; + TT -> P; + TT -> TB -> N -> B; +} diff --git a/images/heidiobj1.png b/images/heidiobj1.png deleted file mode 100644 index 6caa0e3471fe0e5f87254d90eb3782ecbad24403..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2136 zcmY+FdpOhI1IItaBiC=D+$HjjX4ytA%Se_>jHt*p%w-iOW0-s7x~#tCGBK43x#Y5t zYWkX@(ok-rVsn{Xa$Omk?|$|D&x5DB(KSpq;kNpj0iRKP+w7n|ciEkpII05s6HE+_yX{0RWb zX#lVx7)qW2fG7w6%=!WVybu5s!i!s-%>)y|{`NLV0C;pw3nn1(a9ekrAZ>qD>o=Fo z0YJ>z4rzHNW@N$3;;&YSykjAeehPv{*AEztGTl8!!Y(;sdxXqV6qZE3yfg?Gsl9G6 zY2&jlCu}S1RMs~2zV=!BL|iOsU0cW^^IZ3B*)i$$cTMtRW#CsoF!sxc5tn$<|Di|K z`j5GmK$-F37=9V+b#Hd*&$P?(*Z8U}p;pZ-lcF7zZOkx~%Eq>ZJvHPnaaFbRdnHID z-;oI(DP65hmydWZA!`_y8~HH~xtrtKl^pEXB-qJP%81%rSrA2hxIQ#KxS=7kgXu-~ zE=mrb2+rbI6cPUx3)Vrss7BAc(wEu4ANA_m4Sh>HjW7^FKGJ?*@8_OJl`V<gcjxqGh+I zMN(EhuY&CTT``)Rx!1_W>cNuLqh+1=Cqp@;!Bt%aZsCa-C1?Jd@$I9QGrZ63sM_9C zsIu+TgK0-O(KaLpl{>pk+qRIFQuy~6?|9yEtWEYy!7{}6xPYJ@u@Sw4wNi;GW+{-z zM0j1$!jKw5bLF$%L)o}Q<=!Y+QUBs0(7hn@lr5_q)1h1zH@?CVk$&NwMgh@*v7Jw4 zI(X%r*KpEsI5N83ADj3m9(tHFgf65>MZD>n=V^z!%DM3}+|nw8HcMOE10ysu-txGL z5A{>MU@+5tm_~BT$=3Wy@wCcyUW;q!wc)l}G z>et!*C-uIaQrGiLCUI03B3j3-=?q(txf6{LW?Q5}tM(*a<0yh9bfu5?V}_NU?7dj5 zVtfEQR~4J_p|XA&!63&R?)x_Ci_2tU)0L%-%Wg>4>3n?2VM!}|mA@*kz@yaYul7;$ z`pzvwgEV{SDh;F2buX$iRhl|CFYb!4?s>*tl6amt(N<+L@CEr*m3o7iPZ?{l?_)-> zUnDh_ZZ=*)G;)&EIl&pe=w34^AX6(2RAyQ_wOzw0haSZjm@xB0DYy{@#^VJ(owk`1 z@7_o^fN!_+9xNXqI$D7?x9YM>A#+|PZ6e$Lqw_4jZ-)7t7lB6I>KfFVBkYEsc!8CanhVx_T?evH@A#_|Mhip3^PY(ZNiLJEfcxytZ#`%U^V^ zLmMx}%_f>tR%08oU7DS#inr0#?+{6?ob$#Z?OV=1+zxUS-;dGrM@Rx07CTuELCUgO z@A2?MA92O^X2YE!DBN$4u8J*yMsR^#-uWmc7&V z8ArwbC5>Rq{!>+3gJlyC8d?dSD?HnYN*9s>bXUa zMkJZGJ0EcKP|gzLYA7$*>_mLbBf#0Cn(G|ms9`E>S9Jv+Y#wtz^^C$EjjA>4^sSKP zTMbQBU)9>_|2uQPiuheBtwHys(DV1`0^$ZCv63tbcD-!f?h@UUA{b{fE20Ysal9glHlC*z>a=c zlVPzcDlak$m;kbptIg$*S_1k+XARllaXar7Bi%)j5;}f=NxDs~B^kP$DsX-5RkHxIl-MI3+s+zIQ z$Kh4010Ggek#`Z5vYd5R$1yjv!$bJ_pI=xb3^AV_gg8d0E14#z?&!&HkcpNNq)#<{ zf#3a+wb4$$Ac?moMYVh$iiLlo47ssbR8ixyDIQNfRF`JsnZ4MT&yJ%$SpN?u%~d)g zs;5D7f?rlU^2E8w0KdpUI65Lw5C9AUH3CBn!4T*f7!(eJ2?_`Tg+n067mJzy5kj#6 n7lL910tEI;Fg*i30yi{(8=CwUeCPx*fdJT@a75M~_r3BDSeO&{ diff --git a/images/heidiobj2.png b/images/heidiobj2.png deleted file mode 100644 index 255a32a0ef98a84436dbb73c553ec8d6b968fc9b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2272 zcmY+F4LH;58^?b-btsYEC`Q;n5!q%^TVDQ)VJaj=CMz0Bi)t)v=JkYm8xuK{mvBr{ zOx})mkmke)jhQ;4d24Bmyfysy_di|N`Cr%lJooc??)!V+*L_{jbv+5rj&@4h)VBcu zpoFovaRC51vh3`vAlm?|OuAU+Hv6H@pa9@`s-pDD78%Rkaj`oIJnaHa$w1r3-sKDc zgy{i5WGn!z$gUzM0U#I(0G}@d05Tf@)Piyw&YH^to4ili*#H1D8Ehh>twHt|@5sFU z#6*sr^umx3K10SSgz{GaVpUmkQ)i5r=8>hzQkQ-0kPx`aKTq;3sfCzHoo_#Z{! z-w_QL*7)&GB&w(gOy4o{f{lVDo8K(gs0sNub#2cmo?_0>H%h-=){VCe z-L;w2mAEH_BQyYGZuSh-Z?CyNkZ0i)Zj@1)WhKutPh4o*iAgd#i85B9ZBxe0B(pcc z0=X$-s3Qe~Pd6~xAieSUT_hf{{Y|oxceLimpD;x&Fqx4;DI(4;H z#}u?DYU2$JVEc2j=Yosgd+=5!q+MTb{dI{bY1Tae_v*eFpBX>uq_<85N4AT19eYp^ zh49eBE5=g0#9dks%usUUQpxUvF#nv99P(^5&TV_zT;nUHS`8Dp1TQdBbURGNOBh?> z#e8r;|8zsOUA!aLTOBId9lf|E@zvcgB>VH0HqvG^_uHuvU0l_Pf{st<6#E?_klcXku3vuO3t<2am<|;Kf?i5-_K4(sZ zIF0*x8AN|DhZo$~=0<;tmUTZj7BE>OY%%owBNx|wWyPdjzBP&bzzjcfIOF!LVMgic zY^Gq{4NSH4D2I%2HyS`eB622_Gc;ul+^n@!Un(uvu~O7p<+`>oR1ds2ez$$4uahTx z*B|$J)T`e+cF&OU{FB1R)zBgfv6H*$B)GTTuePZ5;QOMvNy1w6{x$QS7Qn~*BiE){ z^DHUmgl#~#wlm}2SHhR0>WF>(tP3a5j_jnqS<8$*DYK8V;@F}&xu}8Lzq~~=rR@V5>8{JJ z4+8PGus%y$a@n%k(z&A6PYZM+OH7j^+Q81yii^`kVp%sF1|j<1q(fS^y6fu0%Q|QA9`9N?e za_PW_6RWLfZNkm5wcji)nvY5_-4S1eXn0-ju=vlMxEg}3(~ZDm^9bvHEsG(&@-k)< zMfvyhzS?xiBkM>;nBk}t#p~1P;`{rFIy&Sn6{cK!MxqR=Y6C*gz7eF93~V7Z z979k2ipqV7F2MTeP@S5-q#SOvQ6PXicCT@d0cPhD_0AyG`#Z=gf}+A!<4~RO#uvH{ z`T>nOUTUnV>&)wwpvs^E)=O`F2RU+A(JhFx(9N&TbmBfbE zX<@oJgMbr%>yQ#rbCrXz{PB&zqiOg%FUiVsE}xG?@IPeQm+4TACTQ}O432eYd+h|- zRYbu4P)*Qg9n^~Z)p(DrOuuePk{*_{-BEbv5;$w;d^j_xG_L{zIk1#3tdgb}bUm3C zARf7e4c-5H+NU9}?#9s^M6_Z?@<^4t`|$}87Lpfe_5#V~Fz zWBYGbAR`*4Usuhj{BkaDN9s6xfc;_NLyBFaI8lmtUNLU{X7__6!)03B@{{tae BWIO-> diff --git a/images/heidiobj3.png b/images/heidiobj3.png deleted file mode 100644 index bfd73a59ffec6760e4d6f43e57364206c5c5b0b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2355 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 diff --git a/images/heidiobj7.png b/images/heidiobj7.png deleted file mode 100644 index 46ab2b7480e62977eef556635143b33f6a45d51f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2519 zcmai0eLT}^8~+g<73SrXWSS^SUD&+C)())0Ve+ zpE{IL8fA7&Uc=-$OD1J3&ack%{BfS=kLUBb@B6yH*L8jG&vjk*{rTKi+RtuSwe?%p z0|21rd>HKs015QtfZG%0{R&p2 zswhRD9^K|VdG1-fON^uN{IY=XB(Jf%^vVr$2u4{!P4lyYoNpl2w4X3c;$f9?C@OH6 zCK?4N6VRI{4qkl2vrBU9XydPCI2s;Yb$h)KClwp`L86O~V&}=J#cDRGPAkOAq$A|s z*8GJ|^XQH4N86(*-wasniebY>%v*_dmBgQNY$-auV%++P(yp z6sm9J=o9x1q z&`anRQ?<+8#;c|Xg?ViorI(d6IaBZJ_ z$o`qP_3Ppt+7_i$a`NGfPy9WKJ%r?Xx)$TkO*%VSC%O70>6`zufbE7lF}cU127i3} zOr{jax_A(t*fpzd#kiAWelksZXg%mh+1jx0kivQ5*K|+oMbltYnH16l(@mWElBO4K zwYEu03+vbRVG(Juh^NhwQ+MbWnpUPOv$>7AAy2yaXE?j6A3*cF5#>RsN_j_@wGfiZ zBs_Doy&h6#kD~DUt;Nd)IARQMtZxMt%nEn93ehBZsW zZMm?U!UGVKV&CAN3CGZtd7hQ_tUk5+6-@k1v&M(`5Yd`j4!`t%VwDvXktmQ8_;qgX zQ+ODuq1y&LgC)h>9|oUoyf3?O_`^CnVSl$7{|=PtyKVJS98Jj;{>P@- zfM*aqRzp>mpi`N`#>PAevHdX^nLgwL&lVbf)7$ApF1&l6qaQ6=Z)H{`s9Wmn$Ts*< z8bGLbDS0`qw_b)UHa?{l=rj_+OI@s(y0LT5(ppCpSyAX9%V#*auD5zuFd>|l8Ou@o4XFf`Rxh!B-bjUpH?gK>=kDeuRJvWf z{=I?wT&@GBqVUOUML$_G>5tACJyjVe^lToke2B^Q-BvC?$G}(GF_B&U%ZMY@t_ca( z!hEf--czoZ{xDnoP++xLYA^Sc42!HPm>3x;YOKNB%C$lkl1y<%oN;!#43%6Cy zuqHl?VJ`(;dmt^{I4EdXubqVnvBVJ*t{uVIUM=m9g!v}4ZG-)8Ch+FUgOrcUdedDz zJI>%eL<8A-=XiNp+6B8x8U70?JKDQaZ;AD4d-|k*;-W7cSH5Rnl-)wjt7#R$;f}y$DTt;0hk$oOZhd_?aX9Qh1jsH6Q zOOwn%da36COf&j=2AR(qbD7WsGiVPMel(J*5n|ME@R5ImpXSDvl6iGKQS)(&5efDa z?pIND$tp|jTj0~x^#7aoKPy5~w}XAKM&&@h7;gSJW*q5&dP@Oo&)6UxBPvd`VU%PM zn)by4v{C{JrWuFvaiiXCU^Jhv1JGRcmJ-vTOj?@r{0PueB533UetmK8f>|b(Eiwgi z*pBRTwX8>blZ#GNc750+yDJ+-B5*iSKRg|=s)pQ)V}+i|g$>f&!6M)}hQeAJ9XE{H z^Gd2C*_6l=+RqcvJ-WN$ywr^ER|nD2oM?OYEgFUDa+V31umQ=OX}tPh-GzpX{CC?i zZZ?N6Qp~)zW*BU8jG{3oqR$3I2io9&4Fm;Xfi&M|irj08H21PFx3RDQhY8Z$28nc- uEgbj<;X?S?kf19d0cr7_VC`jYX|vY~bp4w!nnfQ434k-k4b5`!Px=dC&dV+$#! zPAjOXr`%GSQO6|^buvveazS&e{3sDc7<8`l>0lDE5;lSm#F%v zYzb7Kxn!5PHj)_erE0A3yDcXw?@pd~E@VRby{fTjS8yWmra{-srX3q8c#E^mhM)FG}+9dd`=(3QFF4cXeklLbloe9?82@G zCG|^3h}Y!}oI}@(UM0rD9;B=Sejs$tT2Mme=R|9!RrzGqE?$5z4pg40T=WjYP(bXFSM8I&6kAA~$4t`DrwuiD8iUqDWz zoZO8Z#70?0;$@LfY{H6*&4cJ{ktoja&TM|*jq>+4R8Qwdg6Z*O{$ip57C#rB+1(j( zt#`&rSi<_*2tzZMQ|9#O3adm)3SA>R%=94Y;}p`_r?2XAJtx z)`ZJH-5Z@UX_qh#=8@f-i55wqq#ZzWo&23M`CT4-%y#fM-%{=he|f5P2b2TW^6nzD z+AT{KZ%wvBG!9EIjD(`lwk{E5Q@7!A>2kLjN@M3femQ}RORoueu{~gUSYoExB_qU) z&i)bT-FTB9K4ST`-0+a~ZOm^DN2|{EK^@-Au!rtwaAfF_yRfXzn714stT^+v<4Im^ zqq@H+g33hl`gOo0=jY?}U2h}dWi6|6QKTZEU?NO2d&<6;AK;V z9QCUFSp_?#X20jyK0B^)6K`l+p?7eE@_y>blQF-{hlV__@*;^jJqcoTSbP`Bd#3}o z2Pyq|I>huA`^&=TUZ?tY&MSI50$8PgVmb!@W(?a4Y}DiG3ToHBoc&UDnO^4yRxN;a zzPoO3PA?tIWOgTN_>T^Utq}xyctfTcO~xH*qlPbA#R95&=bjs*$-Xz5wgs@Lx(_Mm zJ5NBi3h*a*vy7f~Ro`Ma?n;a-{5?U?{g%v#1vlRBbGOGPHU4SC3VR+A|4jVbc;ZY+ zRGr+m%B|3QBbb0kh#%d$F_A#aO=4z@@-TL1K;k&LoTB(?9`fx&l3shl@r--z^wXkO zT=tGqsF2z%$bVJwy9M-=Fi8un`!KuDrXxgXPh==8 z_})&D(U=1eE^AG6*BJLc2&Fgo-OCRVc6ZtY^^Y}0H12Jg7PCt<`>xq9Y^3*(rFqMv z;PYl;=0uPPHNBomJHw}&wuFxK6Oq$0Dl0+5lRyy}JpoaVEf3uKUhZm_wuUnvmQsS^c#o8lXLIDjw${?wkcL>?I|HjW_Uf(($uDw zPbof`P5p*yP8WsFoDb7ETPXv&Eyh2ek{rt@{?@iq7dZRN6O)5A3!eAzvm(D)(<>{i zwSJ^+f_}=~iCVn6pTO%4K3L5AxJ6g0*B8D!)3ziUF_u=Na?{_}VP$(a0d6wr$q}6- zPla@65nc!}Cg5NlqiWe}=o!!IK*P+jautZ5{g~6jeZS977em#LFLvkdgXrHC-pCoo=r>;4lwd7Wqyc$sT-#la*qR_JvQnkn9WL|u~Wxh7&Yl&#Ew|0Hg zAH`^9d1K@LhvoS%IWg~0?C4dG10CK%&dY<2eit*@KD6%+pa#hnroEL^)wrm5#tY_` zD?ZYvVwtYBBmCA*v>>3r^R>({Vse9sA)yfcx%`1nR!`x@dVPN3yVRFW=>bK_#RV@gj4p7 zDIiFsmVxwhbMse58y#-(po}EP6Z5jQdT6A>BC}L9RR5?nV;kR9?HB>(Cf5H4Na3)6 zyPQcwtjAwYfyX#~9Ud9YGpI>1#FC)9355RitZc}%6MuKL}fzbRpnq6~m70=dT;fwo2aC!F!e8`CBaPq diff --git a/tools/__init__.py b/tools/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tools/blockdiag.py b/tools/blockdiag.py new file mode 100644 index 0000000..1aca0cf --- /dev/null +++ b/tools/blockdiag.py @@ -0,0 +1,334 @@ +# -*- coding: utf-8 -*- +""" + blockdiag.sphinx_ext + ~~~~~~~~~~~~~~~~~~~~ + + Allow blockdiag-formatted diagrams to be included in Sphinx-generated + documents inline. + + :copyright: Copyright 2010 by Takeshi Komiya. + :license: BSDL. +""" + +from __future__ import absolute_import + +import os +import re +import posixpath +import traceback +import pkg_resources +from collections import namedtuple +from docutils import nodes +from sphinx import addnodes +from sphinx.util.osutil import ensuredir + +import blockdiag.utils.rst.nodes +import blockdiag.utils.rst.directives +from blockdiag.utils.bootstrap import detectfont, Application +from blockdiag.utils.compat import u, string_types +from blockdiag.utils.fontmap import FontMap +from blockdiag.utils.rst.directives import with_blockdiag + +# fontconfig; it will be initialized on `builder-inited` event. +fontmap = None + + +class blockdiag_node(blockdiag.utils.rst.nodes.blockdiag): + def to_drawer(self, image_format, builder, **kwargs): + if 'filename' in kwargs: + filename = kwargs.pop('filename') + else: + filename = self.get_abspath(image_format, builder) + + antialias = builder.config.blockdiag_antialias + transparency = builder.config.blockdiag_transparency + image = super(blockdiag_node, self).to_drawer(image_format, filename, fontmap, + antialias=antialias, transparency=transparency, + **kwargs) + for node in image.diagram.traverse_nodes(): + node.href = resolve_reference(builder, node.href) + + return image + + def get_relpath(self, image_format, builder): + options = dict(antialias=builder.config.blockdiag_antialias, + fontpath=builder.config.blockdiag_fontpath, + fontmap=builder.config.blockdiag_fontmap, + format=image_format, + transparency=builder.config.blockdiag_transparency) + if hasattr(builder, 'imgpath'): # Sphinx (<= 1.2.x) or HTML writer + outputdir = builder.imgpath + else: + outputdir = '' + return posixpath.join(outputdir, self.get_path(**options)) + + def get_abspath(self, image_format, builder): + options = dict(antialias=builder.config.blockdiag_antialias, + fontpath=builder.config.blockdiag_fontpath, + fontmap=builder.config.blockdiag_fontmap, + format=image_format, + transparency=builder.config.blockdiag_transparency) + + if hasattr(builder, 'imagedir'): # Sphinx (>= 1.3.x) + outputdir = os.path.join(builder.outdir, builder.imagedir) + elif hasattr(builder, 'imgpath'): # Sphinx (<= 1.2.x) and HTML writer + outputdir = os.path.join(builder.outdir, '_images') + else: + outputdir = builder.outdir + path = os.path.join(outputdir, self.get_path(**options)) + ensuredir(os.path.dirname(path)) + + return path + + +class Blockdiag(blockdiag.utils.rst.directives.BlockdiagDirective): + node_class = blockdiag_node + + def node2image(self, node, diagram): + return node + + +def resolve_reference(builder, href): + if href is None: + return None + + pattern = re.compile(u("^:ref:`(.+?)`"), re.UNICODE) + matched = pattern.search(href) + if matched is None: + return href + elif not hasattr(builder, 'current_docname'): # ex. latex builder + return matched.group(1) + else: + refid = matched.group(1) + domain = builder.env.domains['std'] + node = addnodes.pending_xref(refexplicit=False) + xref = domain.resolve_xref(builder.env, builder.current_docname, builder, + 'ref', refid, node, node) + if xref: + if 'refid' in xref: + return "#" + xref['refid'] + else: + return xref['refuri'] + else: + builder.warn('undefined label: %s' % refid) + return None + + +def html_render_svg(self, node): + image = node.to_drawer('SVG', self.builder, filename=None, nodoctype=True) + image.draw() + + if 'align' in node['options']: + align = node['options']['align'] + self.body.append('
' % (align, align)) + self.context.append('
\n') + else: + self.body.append('
') + self.context.append('
\n') + + # reftarget + for node_id in node['ids']: + self.body.append('' % node_id) + + # resize image + size = image.pagesize().resize(**node['options']) + self.body.append(image.save(size)) + self.context.append('') + + +def html_render_clickablemap(self, image, width_ratio, height_ratio): + href_nodes = [node for node in image.nodes if node.href] + if not href_nodes: + return + + self.body.append('' % id(image)) + for node in href_nodes: + x1, y1, x2, y2 = image.metrics.cell(node) + + x1 *= width_ratio + x2 *= width_ratio + y1 *= height_ratio + y2 *= height_ratio + areatag = '' % (x1, y1, x2, y2, node.href) + self.body.append(areatag) + + self.body.append('') + + +def html_render_png(self, node): + image = node.to_drawer('PNG', self.builder) + if not os.path.isfile(image.filename): + image.draw() + image.save() + + # align + if 'align' in node['options']: + align = node['options']['align'] + self.body.append('
' % (align, align)) + self.context.append('
\n') + else: + self.body.append('
') + self.context.append('
') + + # link to original image + relpath = node.get_relpath('PNG', self.builder) + if 'width' in node['options'] or 'height' in node['options'] or 'scale' in node['options']: + self.body.append('' % relpath) + self.context.append('') + else: + self.context.append('') + + # tag + original_size = image.pagesize() + resized = original_size.resize(**node['options']) + img_attr = dict(src=relpath, + width=resized.width, + height=resized.height) + + if any(node.href for node in image.nodes): + img_attr['usemap'] = "#map_%d" % id(image) + + width_ratio = float(resized.width) / original_size.width + height_ratio = float(resized.height) / original_size.height + html_render_clickablemap(self, image, width_ratio, height_ratio) + + if 'alt' in node['options']: + img_attr['alt'] = node['options']['alt'] + + self.body.append(self.starttag(node, 'img', '', empty=True, **img_attr)) + + +@with_blockdiag +def html_visit_blockdiag(self, node): + try: + image_format = get_image_format_for(self.builder) + if image_format.upper() == 'SVG': + html_render_svg(self, node) + else: + html_render_png(self, node) + except UnicodeEncodeError: + if self.builder.config.blockdiag_debug: + traceback.print_exc() + + msg = ("blockdiag error: UnicodeEncodeError caught " + "(check your font settings)") + self.builder.warn(msg) + raise nodes.SkipNode + except Exception as exc: + if self.builder.config.blockdiag_debug: + traceback.print_exc() + + self.builder.warn('dot code %r: %s' % (node['code'], str(exc))) + raise nodes.SkipNode + + +def html_depart_blockdiag(self, node): + self.body.append(self.context.pop()) + self.body.append(self.context.pop()) + + +def get_image_format_for(builder): + if builder.format in ('html', 'slides'): + image_format = builder.config.blockdiag_html_image_format.upper() + elif builder.format == 'latex': + if builder.config.blockdiag_tex_image_format: + image_format = builder.config.blockdiag_tex_image_format.upper() + else: + image_format = builder.config.blockdiag_latex_image_format.upper() + else: + image_format = 'PNG' + + if image_format.upper() not in ('PNG', 'PDF', 'SVG'): + raise ValueError('unknown format: %s' % image_format) + + if image_format.upper() == 'PDF': + try: + import reportlab # NOQA: importing test + except ImportError: + raise ImportError('Could not output PDF format. Install reportlab.') + + return image_format + + +def on_builder_inited(self): + # show deprecated message + if self.builder.config.blockdiag_tex_image_format: + self.builder.warn('blockdiag_tex_image_format is deprecated. Use blockdiag_latex_image_format.') + + # initialize fontmap + global fontmap + + try: + fontmappath = self.builder.config.blockdiag_fontmap + fontmap = FontMap(fontmappath) + except: + fontmap = FontMap(None) + + try: + fontpath = self.builder.config.blockdiag_fontpath + if isinstance(fontpath, string_types): + fontpath = [fontpath] + + if fontpath: + config = namedtuple('Config', 'font')(fontpath) + fontpath = detectfont(config) + fontmap.set_default_font(fontpath) + except: + pass + + +def on_doctree_resolved(self, doctree, docname): + if self.builder.format in ('html', 'slides'): + return + + try: + image_format = get_image_format_for(self.builder) + except Exception as exc: + if self.builder.config.blockdiag_debug: + traceback.print_exc() + + self.builder.warn('blockdiag error: %s' % exc) + for node in doctree.traverse(blockdiag_node): + node.parent.remove(node) + + return + + for node in doctree.traverse(blockdiag_node): + try: + with Application(): + relfn = node.get_relpath(image_format, self.builder) + image = node.to_drawer(image_format, self.builder) + if not os.path.isfile(image.filename): + image.draw() + image.save() + + image = nodes.image(uri=relfn, candidates={'*': relfn}, **node['options']) + node.parent.replace(node, image) + except Exception as exc: + if self.builder.config.blockdiag_debug: + traceback.print_exc() + + self.builder.warn('dot code %r: %s' % (node['code'], str(exc))) + node.parent.remove(node) + + +def setup(app): + app.add_node(blockdiag_node, + html=(html_visit_blockdiag, html_depart_blockdiag)) + app.add_directive('blockdiag', Blockdiag) + app.add_config_value('blockdiag_fontpath', None, 'html') + app.add_config_value('blockdiag_fontmap', None, 'html') + app.add_config_value('blockdiag_antialias', False, 'html') + app.add_config_value('blockdiag_transparency', True, 'html') + app.add_config_value('blockdiag_debug', False, 'html') + app.add_config_value('blockdiag_html_image_format', 'PNG', 'html') + app.add_config_value('blockdiag_tex_image_format', None, 'html') # backward compatibility for 1.3.1 + app.add_config_value('blockdiag_latex_image_format', 'PNG', 'html') + app.connect("builder-inited", on_builder_inited) + app.connect("doctree-resolved", on_doctree_resolved) + + return { + 'version': pkg_resources.require('blockdiag')[0].version, + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } -- 2.31.1