diff options
author | Karl Berry <karl@freefriends.org> | 2016-12-06 00:28:11 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2016-12-06 00:28:11 +0000 |
commit | 98c0bc5c3d62d24f3f39fcc797792e70029c65aa (patch) | |
tree | 25cf0a9b31ec1d1c699632069b6a07cd2fcb8446 /Master/texmf-dist/tex | |
parent | 0490ce6a2a0e554c8e241df1699801decea844b8 (diff) |
forest (5dec16)
git-svn-id: svn://tug.org/texlive/trunk@42640 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex')
6 files changed, 2503 insertions, 614 deletions
diff --git a/Master/texmf-dist/tex/latex/forest/forest-compat.sty b/Master/texmf-dist/tex/latex/forest/forest-compat.sty index 4245f103044..4414eb8bc2c 100644 --- a/Master/texmf-dist/tex/latex/forest/forest-compat.sty +++ b/Master/texmf-dist/tex/latex/forest/forest-compat.sty @@ -3,7 +3,7 @@ % forest-index.dtx %% `forest-compat' defines a compatibility layer of package `forest'. %% -%% Copyright (c) 2015 Saso Zivanovic +%% Copyright (c) 2016 Saso Zivanovic %% (Sa\v{s}o \v{Z}ivanovi\'{c}) %% saso.zivanovic@guest.arnes.si %% @@ -23,7 +23,7 @@ %% constituting the package see main source file of the package, %% `forest.dtx', or the derived `forest.sty'. -\ProvidesPackage{forest-compat} +\ProvidesPackage{forest-compat}[2016/12/05] \def\forest@deprecated#1{% \PackageWarning{forest}{Compatibility mode for #1}% @@ -31,23 +31,35 @@ \forestset{@@deprecated/.code={\forest@deprecated{#1}}} \def\forestcompat#1{\pgfqkeys{/forest/@compat}{#1}} \forestcompat{ - silent/.style={\def\forest@deprecated##1{}}, + silent/.code={\def\forest@deprecated##1{}}, %%% begin listing region: compat_keys most/.style={1.0-most}, all/.style={1.0-all}, none/.style={}, 1.0-most/.style={ 1.0-triangle,1.0-linear,1.0-nodewalk,1.0-ancestors, - 1.0-fittotree,1.0-for,1.0-forall + 1.0-fittotree,1.0-for,1.0-forall, + 2.0.2-most, }, 1.0-all/.style={ 1.0-most, 1.0-forstep,1.0-rotate,1.0-stages,1.0-name, 2.0.2-all, }, + 2.0.2-most/.style={ + 2.0-most, + }, 2.0.2-all/.style={ 2.0.2-delayn,2.0.2-wrapnpgfmathargs, + 2.0-all, + }, + 2.0-most/.style={}, + 2.0-all/.style={ + 2.0-most, + 2.0-delayn, + 2.0-edges, }, + 2.0-edges/.style={2.0-anchors,2.0-forkededge,2.0-folder}, %%% end listing region: compat_keys 1.0-triangle/.style={ /forest/triangle/.style={ @@ -106,14 +118,9 @@ }, 1.0-forstep/.code={% \def\forest@forstepwrapper##1##2{% - \def\forest@nodewalk@config@everystep@method{independent}% - \def\forest@nodewalk@config@history@method{independent}% - \edef\forest@marshal{% - \def\noexpand\forest@nodewalk@config@oninvalid{compatfake}% - \unexpanded{\forest@Nodewalk{##1}{##2}}% - \def\noexpand\forest@cn{\forest@cn}% - \def\noexpand\forest@nodewalk@config@oninvalid{\forest@nodewalk@config@oninvalid}% - }\forest@marshal + \forest@forthis{% + \forest@configured@nodewalk{independent}{independent}{compatfake}{##1}{##2}% + }% }% \def\forest@relatednode@option@compat@ignoreinvalidsteps##1{% \forest@saveandrestoremacro\forest@nodewalk@oninvalid{% @@ -172,11 +179,12 @@ }, 2.0.2-delayn/.style={ /forest/delay@n/.style 2 args={ - @@deprecated={propagator "delay n" (it introduces two levels of hash doubling)}, + @@deprecated={propagator "delay n" (it introduces two levels of hash doubling reevaluates the first argument (the desired number of cycles) at every cycle)}, if={##1==1}{delay={##2}}{delay={delay@n/.wrap pgfmath arg={{####1}{##2}}{##1-1}}} }, + 2.0-delayn/.style={}, % this key would patch the same thing! }, - 2.0.2-wrapnpgfmathargs/.code={ + 2.0.2-wrapnpgfmathargs/.code={% \def\forest@wrap@pgfmath@args@@@wrapandpasson{% \forest@deprecated{handler "wrap n pgfmath args" (it introduces two levels of hash doubling)}% \expandafter\expandafter\expandafter\def @@ -186,5 +194,58 @@ \expandafter\pgfkeysalso\expandafter{\expandafter\pgfkeyscurrentpath\expandafter=\expandafter{\forest@wrapped}}% }% }, + 2.0-delayn/.style={ + /forest/delay n/.style 2 args={ + @@deprecated={propagator "delay n" (it reevaluates the first argument (the desired number of cycles) at every cycle)}, + if={##1==0}{##2}{delay@n={##1}{##2}} + }, + /forest/delay@n/.style 2 args={ + if={##1==1}{delay={##2}}{delay={delay@n/.process={P}{##1-1}{##2}}} + }, + }, + 2.0-anchors/.code={% + \csdef{forest@anchor@@parent'}{% + \forest@anchor@isbordertrue + \edef\forest@temp@anchor{\number\numexpr\forestove{grow}-\forestove{rotate}+180}% + } + \csdef{forest@anchor@@parent first'}{% + \forest@anchor@isbordertrue + \edef\forest@temp@anchor@parent{\number\numexpr\forestove{grow}-\forestove{rotate}+180}% + \edef\forest@temp@anchor@first{\number\numexpr\forestove{grow}-\forestove{rotate}\ifnum\forestove{reversed}=0 -\else+\fi90}% + \forest@getaverageangle{\forest@temp@anchor@parent}{\forest@temp@anchor@first}\forest@temp@anchor + } + \csdef{forest@anchor@@parent last'}{% + \forest@anchor@isbordertrue + \edef\forest@temp@anchor@parent{\number\numexpr\forestove{grow}-\forestove{rotate}+180}% + \edef\forest@temp@anchor@last{\number\numexpr\forestove{grow}-\forestove{rotate}\ifnum\forestove{reversed}=0 +\else-\fi90}% + \forest@getaverageangle{\forest@temp@anchor@parent}{\forest@temp@anchor@last}\forest@temp@anchor + } + }, + 2.0-forkededge/.code={% + \forest@iflibraryloaded{edges}{% + \forestset{ + forked edge/.style={ + edge={rotate/.pgfmath=grow()}, + edge path'={(!u.parent anchor) -- ++(\forestoption{fork sep},0) |- (.child anchor)}, + }, + forked edges/.style={ + for tree={parent anchor=children}, + for descendants={child anchor=parent,forked edge} + }, + }% + }{% + \appto\forest@compat@libraries@edges{\forestcompat{2.0-forkededge}}% + }% + }, + 2.0-folder/.code={% + \forest@iflibraryloaded{edges}{% + \expandafter\patchcmd\csname @pgfk@/forest/folder/.@cmd\endcsname + {parent anchor=-children last}{parent anchor=parent last}{}{}% + \expandafter\patchcmd\csname @pgfk@/forest/folder/.@cmd\endcsname + {edge={rotate/.option=!parent.grow},}{edge={rotate/.pgfmath=grow()}}{}{}% + }{% + \appto\forest@compat@libraries@edges{\forestcompat{2.0-folder}}% + }% + }, } \expandafter\forestcompat\expandafter{\forest@compat} diff --git a/Master/texmf-dist/tex/latex/forest/forest-doc.sty b/Master/texmf-dist/tex/latex/forest/forest-doc.sty index 70f84563179..9bffa050280 100644 --- a/Master/texmf-dist/tex/latex/forest/forest-doc.sty +++ b/Master/texmf-dist/tex/latex/forest/forest-doc.sty @@ -1,7 +1,7 @@ %% forest-doc.sty %% `forest-doc.sty` is an auxiliary package needed to compile the documentation of package `forest`. %% -%% Copyright (c) 2015 Saso Zivanovic +%% Copyright (c) 2016 Saso Zivanovic %% (Sa\v{s}o \v{Z}ivanovi\'{c}) %% saso.zivanovic@guest.arnes.si %% @@ -31,7 +31,7 @@ basicstyle=\small\ttfamily,basewidth=0.51em,boxpos=c,pointstyle=\pstyle,moredelim=[is][\pstyle]{~}{~}} %\lst@InstallKeywords{p}{point}{pointstyle}\relax{keywordstyle}{}ld \def\pstyle{\color{darkgreen}} -\def\itemnosep{\vspace{-1.4ex}} +\newcommand\itemnosep[1][0pt]{\vspace{\the\dimexpr-1.4ex+#1}} \lstset{ rangebeginprefix=\ \ \%\%\%\ begin\ listing\ region:\ , rangebeginsuffix=, @@ -230,7 +230,9 @@ \@Repeat{#1}{#2}#2% } \def\spaces#1{\Repeat{#1}\space} - + +\RequirePackage{dingbat} + %%% Local Variables: %%% mode: latex diff --git a/Master/texmf-dist/tex/latex/forest/forest-index.sty b/Master/texmf-dist/tex/latex/forest/forest-index.sty index e470d5ffe9e..6bd6fb774ed 100644 --- a/Master/texmf-dist/tex/latex/forest/forest-index.sty +++ b/Master/texmf-dist/tex/latex/forest/forest-index.sty @@ -8,7 +8,7 @@ %% %% `forest-index' is an indexing system for the documentation of package `forest', using the package itself. %% -%% Copyright (c) 2015 Saso Zivanovic +%% Copyright (c) 2016 Saso Zivanovic %% (Sa\v{s}o \v{Z}ivanovi\'{c}) %% saso.zivanovic@guest.arnes.si %% @@ -42,10 +42,8 @@ {\let\forestindex@resolvekey\forestindex@resolvekey@shortorlong}% \forestindex@index{example}{#1}{#3}} \DeclareDocumentCommand\indexitem{D(){} O{} t> m}{% - \IfBooleanTF{#3} - {\let\forestindex@resolvekey\forestindex@resolvekey@long} - {\let\forestindex@resolvekey\forestindex@resolvekey@shortorlong}% - \forestindex@index{definition}{default={#1},print format=item,#2}{#4}} + \let\forestindex@resolvekey\forestindex@resolvekey@long + \forestindex@index{definition}{default={#1},#2,print format+=item}{#4}} \DeclareDocumentCommand\indexset{O{} t> m}{% \IfBooleanTF{#2} {\let\forestindex@resolvekey\forestindex@resolvekey@long} @@ -58,15 +56,24 @@ \forestindex@index{#1}{#2}{#4}% } \def\forestindex@index#1#2#3{% - \forcsvlist{\forestindex@forkey{#1}{#2}}{#3}% + {\forcsvlist{\forestindex@forkey{#1}{#2}}{#3}}% } \def\forestindex@forkey#1#2#3{% \forestindex@resolvekey{#3}% - \forestset{@index/.process args={__o}{#1}{#2}{\forestindex@fullkey}}% + %\forestset{@index/.process={__o}{#1}{#2}{\forestindex@fullkey}} + \edef\forest@marshal{% + \noexpand\forestindex@index@{% + {\unexpanded{#1}}% + {\unexpanded{#2}}% + {\expandonce{\forestindex@fullkey}}% + }% + }\forest@marshal } +\def\forestindex@index@#1{\forestset{@index/.process={__o}#1}} \forestset{ declare boolean register=print, declare boolean register=index, + declare boolean register=short, short, declare toks={key}{}, declare toks={argument}{}, declare toks={index key}{}, @@ -99,10 +106,11 @@ if n=0{ content/.option=key, }{ - content/.wrap 2 pgfmath args={##1>##2}{content("!parent")}{key}, + content/.process={OOw2} {!parent.content} {key} {##1>##2}, } }{}, for root'={ + if strequal/.process={O}{!root.name}{@unknown}{TeX=\global\forest@memoizing@ok@false}{}, for tree={ print form/.option=key, index key/.option=key, @@ -113,7 +121,7 @@ every index begin, #1, }, - for reverse={ancestors}{on invalid={fake}{@@index/\forestoption{name}/.try}}, + for reverse={current and ancestors}{on invalid={fake}{@@index/\forestoption{name}/.try}}, if index entry type={definition}{}{% on invalid={fake}{@@index/\forestoption{name}/.try}, }, @@ -125,11 +133,11 @@ if index entry type={definition}{save@foridx}{}, }, stage={}, - if={index()||print()}{ + if index={ index@hypertarget/.expanded={.\forestoption{index key}}, for descendants={ - index@hypertarget/.wrap 2 pgfmath args={##1.##2}% - {index@hypertarget("!parent")}{index_key}, + index@hypertarget/.process= {OOw2} + {!parent.index@hypertarget} {index key} {##1.##2}, }, }{}, if index={ @@ -164,11 +172,11 @@ }, }, temptoksa={}, - result={}, + result'={}, if n children=0{tempboola}{not tempboola}, where index form={}{}{ - if tempboola={temptoksd/.expanded={\noexpand\protect\noexpand\hypertarget{% - \forestoption{index@hypertarget}}{}}}{temptoksd={}}, + temptoksd/.expanded={\noexpand\protect\noexpand\hypertarget{% + \forestoption{index@hypertarget}}{}}, result+/.expanded={% \forestregister{temptoksa}% \forestoption{index key}% @@ -180,7 +188,7 @@ temptoksb={}, }, result+/.expanded={|indexpagenumber\forestregister{index entry type}}, - TeX/.expanded={\noexpand\forestindex@LaTeX@index{\forestregister{result}}}, + TeX and memoize/.expanded={\noexpand\forestindex@LaTeX@index{\forestregister{result}}}, }, endgroup }{}, @@ -192,7 +200,7 @@ process keylist'={print format}{current}, print form/.register=result, }, - for first leaf'={TeX={\forestoption{print form}}}, + for first leaf'={TeX and memoize/.expanded={\forestoption{print form}}}, endgroup, }{}, } @@ -216,8 +224,8 @@ name'/.option=key, content={#1}, }{ - name'/.wrap 2 pgfmath args={##1>##2}{name("!parent")}{key}, - content/.wrap pgfmath arg={##1>#1}{content("!parent")}, + name'/.process={OOw2} {!parent.name} {key} {##1>##2}, + content/.process={Ow1} {!parent.content} {##1>#1}, }, } }, @@ -227,29 +235,33 @@ Autoforward register={set}{##1}, save@session/.style={@@index/\forestoption{name}/.global style/.register=set}, save@foridx/.style={ - if={strequal(name("!root"),"@unknown")}{}{ + if strequal/.process={O}{!root.name}{@unknown}{}{ if set={}{}{ - TeX={% - \immediate\write\forestindex@out{% - \string\indexloadsettings{\forestoption{name}}{\forestregister{set}}% + TeX and memoize/.expanded={% + \noexpand\immediate\noexpand\write\noexpand\forestindex@out{% + \noexpand\string\noexpand\indexloadsettings\noexpand\unexpanded{{\forestoption{name}}{\forestregister{set}}}% }% }, }, - if={strequal(key(),content())}{}{ - TeX={% - \immediate\write\forestindex@out{% - \string\indexdefineshortkey{\forestoption{key}}{\forestoption{content}}% + }, + if key/.process={O}{content} {} {% + if short={ + TeX and memoize/.expanded={% + \noexpand\immediate\noexpand\write\noexpand\forestindex@out{% + \noexpand\string\noexpand\indexdefineshortkey\noexpand\unexpanded{{\forestoption{key}}{\forestoption{content}}}% }% - } + }{}% } } - }, + } } \def\indexloadsettings#1#2{% \pgfkeysifdefined{/forest/@@index/#1/.@cmd}{% \forestindex@loadsettings@warning{#1}% }{}% - \forestset{@@index/#1/.global style={#2}}% + % #s in #2 are doubled; the following \def removes one layer of doubling + \def\forest@temp{#2}% + \forestset{@@index/#1/.global style/.expand once=\forest@temp}% } \def\forestindex@loadsettings@warning#1{% \PackageWarning{forest-index}{Forest index key "#1" was configured more than once! @@ -304,8 +316,8 @@ normal color/.initial=blue, definition color/.initial=red, example color/.initial=darkgreen, - print in color/.style={if stage={print}{result=\protect\textcolor{% - \pgfkeysvalueof{/forest/#1 color}}{##1}}{}}, + print in color/.style={if stage={print}{result/.expanded=\noexpand\protect\noexpand\textcolor{% + \pgfkeysvalueof{/forest/#1 color}}{\unexpanded{##1}}}{}}, print in color/.default=\forestregister{index entry type}, hyper/.style={ if stage={index}{}{ @@ -340,9 +352,10 @@ \forestset{ declare toks register=default, default={}, - item/.style={result/.wrap 4 pgfmath args={% - \item[,##2,##3]{##4}% - }{}{default}{print_form("!parent")}{result}, + item/.style={ + result/.process= {_RORw4} + {} {default} {!parent.print form} {result} + {\item[,##2,##3]{##4}}, }, } \pgfkeys{/handlers/.global style/.code=\pgfkeys{\pgfkeyscurrentpath/.global code=\pgfkeysalso{#1}}} @@ -359,9 +372,84 @@ \pgfkeys@temptoks{#2}\expandafter\xdef\csname pgfk@#1\endcsname{\the\pgfkeys@temptoks}% } \forestset{ + % unlike pgfmath function strequal, |if strequal| does not expand the compared args! + if strequal/.code n args={4}{\ifstrequal{#1}{#2}{\pgfkeysalso{#3}}{\pgfkeysalso{#4}}}, +} +\forestset{ begingroup/.code={\begingroup}, endgroup/.code={\endgroup}, } +\newtoks\forest@memo@key +\newtoks\forest@memo +\newif\ifforest@memoizing@now@ +\newif\ifforest@memoizing@ok@ +\newif\ifforest@execandmemoize@ +\def\forest@memoize#1{% #1 = \cs + \cslet{forest@memo@orig@\string#1}#1% + \def#1##1{% + \ifforest@memoizing@now@ + \forest@globalsaveandrestoreifcs{forest@execandmemoize@}{% + \global\forest@execandmemoize@false + \csname forest@memo@orig@\string#1\endcsname{##1}% + }% + \else + \expandafter\global\expandafter\forest@memo@key\expandafter{\detokenize{forest@memo@#1{##1}}}% + \ifcsname\the\forest@memo@key\endcsname + \@escapeifif{\csname\the\forest@memo@key\endcsname}% + \else + \@escapeifif{% + \global\forest@memo{}% + \global\forest@memoizing@ok@true + \global\forest@memoizing@now@true + \global\forest@execandmemoize@true + \csname forest@memo@orig@\string#1\endcsname{##1}% + \global\forest@execandmemoize@false + \global\forest@memoizing@now@false + \ifforest@memoizing@ok@ + \csxdef{\the\forest@memo@key}{\the\forest@memo}% + \immediate\write\forest@memo@out{% + \noexpand\forest@memo@load{\the\forest@memo@key}{\the\forest@memo}% + }% + \fi + }% + \fi + \fi + }% +} +\def\forest@memo@load#1#2{% + \def\forest@temp@key{#1}% + \def\forest@temp@value{#2}% + \csxdef{\detokenize\expandafter{\forest@temp@key}}{\expandonce\forest@temp@value}% + \immediate\write\forest@memo@out{% + \noexpand\forest@memo@load{\detokenize\expandafter{\forest@temp@key}}{\detokenize\expandafter{\forest@temp@value}}% + }% +} +\forestset{ + TeX and memoize/.code={\forest@execandmemoize{#1}}, +} +\def\forest@execandmemoize#1{% + \ifforest@execandmemoize@ + \let\forest@memo@next\forest@execandmemoize@ + \else + \let\forest@memo@next\@gobble + \fi + \forest@memo@next{#1}% + #1% +} +\def\forest@execandmemoize@#1{% + \gapptotoks\forest@memo{#1}% +} +\def\forest@memo@filename{\jobname.memo} +\newwrite\forest@memo@out +\immediate\openout\forest@memo@out=\forest@memo@filename.tmp +\IfFileExists{\forest@memo@filename}{% + \input\forest@memo@filename\relax +}{}% +\AtEndDocument{% + \immediate\closeout\forest@memo@out + \forest@file@copy{\forest@memo@filename.tmp}{\forest@memo@filename}% +} +\forest@memoize\forestindex@index@ \index(not print,not index)[% set={ index key=unknown, diff --git a/Master/texmf-dist/tex/latex/forest/forest-lib-edges.sty b/Master/texmf-dist/tex/latex/forest/forest-lib-edges.sty index 5c737aabfeb..e982d849f2c 100644 --- a/Master/texmf-dist/tex/latex/forest/forest-lib-edges.sty +++ b/Master/texmf-dist/tex/latex/forest/forest-lib-edges.sty @@ -8,7 +8,7 @@ %% %% `forest-libs' is a collection of libraries for package `forest'. %% -%% Copyright (c) 2015 Saso Zivanovic +%% Copyright (c) 2016 Saso Zivanovic %% (Sa\v{s}o \v{Z}ivanovi\'{c}) %% saso.zivanovic@guest.arnes.si %% @@ -29,30 +29,33 @@ %% `forest.dtx', or the derived `forest.sty'. %% \RequirePackage{forest} -\ProvidesForestLibrary{edges}[2015/11/14 v0.1] +\ProvidesForestLibrary{edges}[2016/12/05 v0.1.1] \forestset{ declare dimen={fork sep}{0.5em}, - forked edge/.style={ - edge={rotate/.pgfmath=grow()}, + forked edge'/.style={ + edge={rotate/.option=!parent.grow}, edge path'={(!u.parent anchor) -- ++(\forestoption{fork sep},0) |- (.child anchor)}, }, - forked edges/.style={ - for tree={parent anchor=children}, - for descendants={child anchor=parent,forked edge} + forked edge/.style={ + on invalid={fake}{!parent.parent anchor=children}, + child anchor=parent, + forked edge', }, + forked edges/.style={for nodewalk={#1}{forked edge}}, + forked edges/.default=tree, } \forestset{ declare dimen register=folder indent, folder indent=.45em, folder/.style={ - parent anchor=parent last, + parent anchor=-children last, anchor=parent first, calign=child, calign primary child=1, for children={ child anchor=parent, anchor=parent first, - edge={rotate/.pgfmath=grow()}, + edge={rotate/.option=!parent.grow}, edge path'/.expanded={ ([xshift=\forestregister{folder indent}]!u.parent anchor) |- (.child anchor) }, diff --git a/Master/texmf-dist/tex/latex/forest/forest-lib-linguistics.sty b/Master/texmf-dist/tex/latex/forest/forest-lib-linguistics.sty index 9632361e964..9c3b9228ac5 100644 --- a/Master/texmf-dist/tex/latex/forest/forest-lib-linguistics.sty +++ b/Master/texmf-dist/tex/latex/forest/forest-lib-linguistics.sty @@ -8,7 +8,7 @@ %% %% `forest-libs' is a collection of libraries for package `forest'. %% -%% Copyright (c) 2015 Saso Zivanovic +%% Copyright (c) 2016 Saso Zivanovic %% (Sa\v{s}o \v{Z}ivanovi\'{c}) %% saso.zivanovic@guest.arnes.si %% diff --git a/Master/texmf-dist/tex/latex/forest/forest.sty b/Master/texmf-dist/tex/latex/forest/forest.sty index 16c96a52e44..dedd3159561 100644 --- a/Master/texmf-dist/tex/latex/forest/forest.sty +++ b/Master/texmf-dist/tex/latex/forest/forest.sty @@ -8,7 +8,7 @@ %% %% `forest' is a `pgf/tikz'-based package for drawing (linguistic) trees. %% -%% Copyright (c) 2015 Saso Zivanovic +%% Copyright (c) 2016 Saso Zivanovic %% (Sa\v{s}o \v{Z}ivanovi\'{c}) %% saso.zivanovic@guest.arnes.si %% @@ -44,7 +44,7 @@ %% - LICENCE %% To use the package, only the files marked with + need to be installed. %% -\ProvidesPackage{forest}[2016/04/09 v2.0.3 Drawing (linguistic) trees] +\ProvidesPackage{forest}[2016/12/05 v2.1 Drawing (linguistic) trees] \RequirePackage{tikz}[2013/12/13] \usetikzlibrary{shapes} @@ -58,7 +58,74 @@ \RequirePackage{environ} \RequirePackage{xparse} - +\RequirePackage{inlinedef} +\newtoks\ID@usercommands{} +\newcommand\NewInlineCommand[3][0]{% + \newcommand#2[#1]{#3}% + \ID@usercommands\xa{% + \the\ID@usercommands + \ifx\@foo#2% + \def\next{\ID@expandunsafe#2}% + \fi + }% +} +\def\@ExpandIfTF#1{% + \csname + % I'm not 100% sure if this plays well in every situation + \csname if#1\endcsname + @firstoftwo% + \else + @secondoftwo% + \fi + \endcsname +} +\patchcmd{\ID@switch} + {\ifcat\noexpand\@foo\space} + {\the\ID@usercommands\ifcat\noexpand\@foo\space} + {% + \NewInlineCommand[2]\ExpandIfT{% + \MultiExpand{3}{% + \@ExpandIfTF{#1}{#2}{}% + }% + } + \NewInlineCommand[2]\ExpandIfF{% + \MultiExpand{3}{% + \@ExpandIfTF{#1}{}{#2}% + }% + } + \NewInlineCommand[3]\ExpandIfTF{% + \MultiExpand{3}{% + \@ExpandIfTF{#1}{#2}{#3}% + }% + }% + \newcommand\InlineNoDef[1]{% + \begingroup + % Define a few ``quarks'' + \def\Expand{\Expand}\def\Super{\Super}% + \def\UnsafeExpand{\UnsafeExpand}\def\MultiExpand{\MultiExpand}% + \def\Recurse{\Recurse}\def\NoExpand{\NoExpand}% + \def\Q@END{\Q@END}% + % Define a toks register + \ID@toks{}% + % Signal that we need to look for a star + \@testtrue\ID@starfalse\ID@starstarfalse\ID@bangfalse + % Start scanning for \def or \gdef + \ID@scan#1\Q@END{}% + \expandafter\endgroup + %\expandafter\@firstofone + \the\ID@toks + }% + }% + {% + \PackageWarning{forest}{Could not patch inlinedef! Disabling it. Except in some special situations (nested arrays), stuff will probably still work, but there's no guarantee. Please report this situation to the author (but check first if a new version already exists).}{}% + \let\Inline\relax + \def\Expand#1{#1}% + \def\MultiExpand#1#2{#2}% + \def\InlineNoDef#1{#1}% + \def\ExpandIfT#1#2{\@ExpandIfTF{#1}{#2}{}}% + \def\ExpandIfF#1#2{\@ExpandIfTF{#1}{}{#2}}% + \def\ExpandIfTF#1#2#3{\@ExpandIfTF{#1}{#2}{#3}}% + } \pgfkeys{/forest/.is family} \def\forestset#1{\pgfqkeys{/forest}{#1}} \newif\ifforest@external@ @@ -66,12 +133,15 @@ \newif\ifforest@install@keys@to@tikz@path@ \newif\ifforestdebugnodewalks \newif\ifforestdebugdynamics +\newif\ifforestdebugprocess +\newif\ifforestdebugtemp +\newif\ifforestdebug \def\forest@compat{} \forestset{package@options/.cd, external/.is if=forest@external@, tikzcshack/.is if=foresttikzcshack, tikzinstallkeys/.is if=forest@install@keys@to@tikz@path@, - compat/.store in=\forest@compat, + compat/.code={\appto\forest@compat{,#1}}, compat/.default=most, .unknown/.code={% load library \eappto\forest@loadlibrarieslater{% @@ -79,10 +149,11 @@ \noexpand\forestapplylibrarydefaults{\pgfkeyscurrentname}% }% }, - debug/.code={\pgfqkeys{/forest/package@options/debug}{#1}}, - debug/.default={nodewalks,dynamics}, + debug/.code={\forestdebugtrue\pgfqkeys{/forest/package@options/debug}{#1}}, + debug/.default={nodewalks,dynamics,process}, debug/nodewalks/.is if=forestdebugnodewalks, debug/dynamics/.is if=forestdebugdynamics, + debug/process/.is if=forestdebugprocess, } \forest@install@keys@to@tikz@path@true \foresttikzcshacktrue @@ -93,10 +164,17 @@ \forcsvlist\useforestlibrary@@{#3}% \IfBooleanT{#1}{\forestapplylibrarydefaults{#3}}% } -\def\useforestlibrary@#1#2{\RequirePackage[#1]{forest-lib-#2}} +\def\useforestlibrary@#1#2{% + \RequirePackage[#1]{forest-lib-#2}% + \csuse{forest@compat@libraries@#2}% +} \def\forestapplylibrarydefaults#1{\forcsvlist\forestapplylibrarydefaults@{#1}} \def\forestapplylibrarydefaults@#1{\forestset{libraries/#1/defaults/.try}} -\NewDocumentCommand\ProvidesForestLibrary{m O{}}{\ProvidesPackage{forest-lib-#1}[#2]} +\NewDocumentCommand\ProvidesForestLibrary{m O{}}{% + \ProvidesPackage{forest-lib-#1}[#2]% + \csdef{forest@libraries@loaded@#1}{}% +} +\def\forest@iflibraryloaded#1#2#3{\ifcsdef{forest@libraries@loaded@#1}{#2}{#3}} \ProcessPgfPackageOptions{/forest/package@options} \def\forest@patch#1#2#3#4#5{% % #1 = cs to be patched @@ -120,9 +198,25 @@ }{% \edef#1{{\pgf@pt@aa}{\pgf@pt@ab}{\pgf@pt@ba}{\pgf@pt@bb}{\the\pgf@pt@x}{\the\pgf@pt@y}}% } +\def\forest@empty{} \long\def\@escapeif#1#2\fi{\fi#1} \long\def\@escapeifif#1#2\fi#3\fi{\fi\fi#1} \long\def\@escapeififif#1#2\fi#3\fi#4\fi{\fi\fi\fi#1} +\def\forest@repeat@n@times#1{% #1=n, #2=code + \expandafter\forest@repeat@n@times@\expandafter{\the\numexpr#1}} +\def\forest@repeat@n@times@#1{% + \ifnum#1>0 + \@escapeif{% + \expandafter\forest@repeat@n@times@@\expandafter{\the\numexpr#1-1}% + }% + \else + \expandafter\@gobble + \fi +} +\def\forest@repeat@n@times@@#1#2{% + #2% + \forest@repeat@n@times@{#1}{#2}% +} \def\newloop#1{% \count@=\escapechar \escapechar=-1 @@ -398,6 +492,7 @@ \def\forest@temp@macro####1{#4}% \csname forest@temp#5\endcsname \edef\forest@temp@value{\ifforest@temp\expandafter\forestOv\expandafter{\expandafter\forest@setter@node\expandafter}\else\expandafter\forestrv\fi{#2}}% + %\expandafter\expandafter\expandafter\pgfkeysalso\expandafter\expandafter\expandafter{\expandafter\forest@temp@macro\expandafter{\forest@temp@value}}% ??? how many expansions are really needed? \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\pgfkeysalso\expandafter\expandafter\expandafter{\expandafter\forest@temp@macro\expandafter{\forest@temp@value}}% }% }{}% @@ -449,6 +544,690 @@ \fi }% } +\forestset{ + show register/.code={% + \forestrget{#1}\foresttemp + \typeout{Forest register "#1"=\expandafter\detokenize\expandafter{\foresttemp}}% + }, +} +\def\forest@newarray#1{% + \forest@tempfalse % non-global + {% + \escapechar=-1 + \expandafter\escapechar\expandafter\count@\expandafter + }% + \expandafter\forest@newarray@\expandafter{\string#1}% +} +\def\forest@newglobalarray#1{% + \forest@temptrue % global + {% + \escapechar=-1 + \expandafter\escapechar\expandafter\count@\expandafter + }% + \expandafter\forest@newarray@\expandafter{\string#1}% +} +\def\forest@array@empty@error#1{% + \PackageError{forest}{Cannot pop from empty array "#1".}{}}% +\def\forest@array@oub@error#1#2{% + \PackageError{forest}{#2 is out of bounds of array "#1" + (\the\csuse{#1M}--\the\csuse{#1N}).}{}}% +\def\forest@newarray@#1{% + % array bounds: M <= i < N + \expandafter\newcount\csname#1M\endcsname + \expandafter\newcount\csname#1N\endcsname + \csedef{#1clear}{% + \ifforest@temp\global\fi\expandonce{\csname#1M\endcsname}0 + \ifforest@temp\global\fi\expandonce{\csname#1N\endcsname}0 + }% + \csedef{#1ifempty}{% + \noexpand\ifnum\expandonce{\csname#1M\endcsname}<\expandonce{\csname#1N\endcsname}\relax + \unexpanded{\expandafter\@secondoftwo + \else + \expandafter\@firstoftwo + \fi}% + }% + \csedef{#1length}{% a numexpr + \noexpand\numexpr\expandonce{\csname#1N\endcsname}-\expandonce{\csname#1M\endcsname}\relax + }% + \csedef{#1checkrange}##1##2{% args can be \numexprs + \noexpand\forest@tempfalse + \noexpand\ifnum\numexpr##1<\expandonce{\csname#1M\endcsname}\relax + \noexpand\forest@temptrue + \noexpand\fi + \noexpand\ifnum\numexpr##2>\expandonce{\csname#1N\endcsname}\relax + \noexpand\forest@temptrue + \noexpand\fi + \noexpand\ifforest@temp + \noexpand\forest@array@oub@error{#1}{Range "\noexpand\number\noexpand\numexpr##1\relax--\noexpand\number\noexpand\numexpr##2\relax"}% + \noexpand\fi + }% + \csedef{#1checkindex}##1{% arg can be a \numexpr + \noexpand\forest@tempfalse + \noexpand\ifnum\numexpr##1<\expandonce{\csname#1M\endcsname}\relax + \noexpand\forest@temptrue + \noexpand\fi + \noexpand\ifnum\numexpr##1<\expandonce{\csname#1N\endcsname}\relax + \noexpand\else + \noexpand\forest@temptrue + \noexpand\fi + \noexpand\ifforest@temp + \noexpand\forest@array@oub@error{#1}{Index "\noexpand\number\noexpand\numexpr##1\relax"}% + \noexpand\fi + }% + \csedef{#1get}##1##2{% ##1 = index, ##2 = receiving cs + \expandonce{\csname#1checkindex\endcsname}{##1}% + \noexpand\letcs##2{#1##1}% + }% + \csedef{#1get@}##1##2{% ##1 = index, ##2 = receiving cs (don't check bounds) + \noexpand\letcs##2{#1##1}% + }% + \csedef{#1toppop}##1{% ##1 = receiving cs + \expandonce{\csname#1ifempty\endcsname}{% + \noexpand\forest@array@empty@error{#1}% + }{% + \ifforest@temp\global\fi\advance\expandonce{\csname#1N\endcsname}-1 + \noexpand\letcs\noexpand##1{#1\noexpand\the\expandonce{\csname#1N\endcsname}}% + }% + }% + \InlineNoDef{\csdef{#1bottompop}##1{% ##1 = receiving cs + \Expand{\csname#1ifempty\endcsname}{% + \forest@array@empty@error{#1}% + }{% + \letcs##1{#1\the\Expand{\csname#1M\endcsname}}% + \ExpandIfT{forest@temp}\global\advance\Expand{\csname#1M\endcsname 1}% + }% + }}% + % \csdef{#1bottompop}##1{}% we need this as \Inline chokes on \let\macro=\relax + % \expandafter\Inline\expandafter\def\csname#1bottompop\endcsname##1{% ##1 = receiving cs + % \Expand{\csname#1ifempty\endcsname}{% + % \forest@array@empty@error{#1}% + % }{% + % \letcs##1{#1\the\Expand{\csname#1M\endcsname}}% + % \ExpandIfT{forest@temp}\global\advance\Expand{\csname#1M\endcsname 1}% + % }% + % }% + % \csedef{#1bottompop}##1{% ##1 = receiving cs + % \expandonce{\csname#1ifempty\endcsname}{% + % \noexpand\forest@array@empty@error{#1}% + % }{% + % \noexpand\letcs\noexpand##1{#1\noexpand\the\expandonce{\csname#1M\endcsname}}% + % \ifforest@temp\global\fi\advance\expandonce{\csname#1M\endcsname}1 + % }% + % }% + \csedef{#1setappend}##1{% ##1 = definition + \ifforest@temp\noexpand\csxdef\else\noexpand\csedef\fi + {#1\noexpand\the\expandonce{\csname#1N\endcsname}}% + {\noexpand\unexpanded{##1}}% + \ifforest@temp\global\fi\advance\expandonce{\csname#1N\endcsname}1 + }% + \csedef{#1setappend@}##1##2{% ##1 = continue by, ##2 = definition + \ifforest@temp\noexpand\csxdef\else\noexpand\csedef\fi + {#1\noexpand\the\expandonce{\csname#1N\endcsname}}% + {\noexpand\unexpanded{##2}}% + \ifforest@temp\global\fi\advance\expandonce{\csname#1N\endcsname}1 + ##1% + }% + \csedef{#1setprepend}##1{% ##1 = definition + \ifforest@temp\global\fi\advance\expandonce{\csname#1M\endcsname}-1 + \ifforest@temp\noexpand\csxdef\else\noexpand\csedef\fi + {#1\noexpand\the\expandonce{\csname#1M\endcsname}}% + {\noexpand\unexpanded{##1}}% + }% + \csedef{#1esetappend}##1{% ##1 = definition + \ifforest@temp\noexpand\csxdef\else\noexpand\csedef\fi{#1\noexpand\the\expandonce{\csname#1N\endcsname}}{##1}% + \ifforest@temp\global\fi\advance\expandonce{\csname#1N\endcsname}1 + }% + \csedef{#1esetprepend}##1{% ##1 = definition + \ifforest@temp\global\fi\advance\expandonce{\csname#1M\endcsname}-1 + \ifforest@temp\noexpand\csxdef\else\noexpand\csedef\fi{#1\noexpand\the\expandonce{\csname#1M\endcsname}}{##1}% + }% + \csedef{#1letappend}##1{% ##1 = cs + \ifforest@temp\noexpand\expandafter\noexpand\global\fi\noexpand\expandafter\noexpand\let + \noexpand\csname#1\noexpand\the\expandonce{\csname#1N\endcsname}\noexpand\endcsname + ##1% + \ifforest@temp\global\fi\advance\expandonce{\csname#1N\endcsname}1 + }% + \csedef{#1letprepend}##1{% ##1 = cs + \ifforest@temp\global\fi\advance\expandonce{\csname#1M\endcsname}-1 + \ifforest@temp\noexpand\expandafter\noexpand\global\fi\noexpand\expandafter\noexpand\let + \noexpand\csname#1\noexpand\the\expandonce{\csname#1M\endcsname}\noexpand\endcsname + ##1% + }% + \csedef{#1values}{% + \noexpand\expandafter\noexpand\expandafter\noexpand\expandafter\expandonce{\csname#1valuesfromrange\endcsname}% + \noexpand\expandafter\noexpand\expandafter\noexpand\expandafter{% + \noexpand\expandafter\noexpand\the + \noexpand\expandafter\expandonce{\csname#1M\endcsname}% + \noexpand\expandafter}% + \noexpand\expandafter{\noexpand\the\expandonce{\csname#1N\endcsname}}% + }% + \csedef{#1valuesfromrange}##1##2{% ##1/##2 = lower/upper bounds (we receive them expanded) + \noexpand\ifnum##1<##2 + {\noexpand\expandafter\noexpand\expandonce\noexpand\expandafter{\noexpand\csname#1##1\noexpand\endcsname}}% here we add braces (for the general case, we might want an arbitrary prefix&suffix) + \noexpand\expandafter\noexpand\@escapeif\noexpand\expandafter{\noexpand\expandafter\expandonce{\csname#1valuesfromrange\endcsname}% + \noexpand\expandafter{\noexpand\number\noexpand\numexpr##1+1}{##2}}% + \noexpand\fi + }% + \csdef{#1topextend}{\def\forest@array@currentarray{#1}\forest@array@topextend}% +} +\def\forest@array@topextend{\futurelet\forest@ate@next@token\forest@ate@checkforspace} +\def\forest@ate@checkforspace{% + \expandafter\ifx\space\forest@ate@next@token + \expandafter\forest@ate@havespace + \else + \expandafter\forest@ate@checkforgroup + \fi +} +\def\forest@ate@havespace{\expandafter\forest@array@topextend\romannumeral-`0}% +\def\forest@ate@checkforgroup{% + \ifx\forest@ate@next@token\bgroup + \expandafter\forest@ate@appendgroup + \else + \expandafter\forest@ate@checkforeov + \fi +} +\def\forest@ate@appendgroup{% + \expandonce{\csname\forest@array@currentarray setappend@\endcsname}\forest@array@topextend +} +\def\forest@ate@checkforeov{% + \ifx\forest@ate@next@token\forest@eov + \expandafter\forest@ate@finish + \else + \expandafter\forest@ate@appendtoken + \fi +} +\def\forest@ate@appendtoken#1{% + \expandonce{\csname\forest@array@currentarray setappend\endcsname}{#1}% + \forest@array@topextend +} +\def\forest@ate@finish\forest@eov{\forest@topextend@next} +\let\forest@topextend@next\relax +\forest@newarray\forest@temparray@ +\forest@newglobalarray\forest@global@temparray@ +\def\forest@eon{ } +\newif\ifforest@isnum@minus +\newif\ifforest@isnum +\def\forest@isnum#1{% + \forest@isnum@minusfalse + \let\forest@isnum@next\forest@isnum@finish + \edef\forest@isnum@temp{#1}% + \expandafter\forest@isnum@a\forest@isnum@temp\forest@eon\forest@eon\forest@END + \ifforest@isnum + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi +} +\def\forest@isnum@a{\futurelet\forest@isnum@token\forest@isnum@b} +\def\forest@isnum@minustoggle{% + \ifforest@isnum@minus\forest@isnum@minusfalse\else\forest@isnum@minustrue\fi +} +\def\forest@isnum@b{% + \let\forest@next\forest@isnum@p + \ifx-\forest@isnum@token + \forest@isnum@minustoggle + \let\forest@next\forest@isnum@c + \else + \ifx+\forest@isnum@token + \let\forest@next\forest@isnum@c + \else + \expandafter\ifx\space\forest@isnum@token + \let\forest@next\forest@isnum@s + \fi + \fi + \fi + \forest@next +} +\def\forest@isnum@c#1{\forest@isnum@a}% +\def\forest@isnum@s#1{\forest@isnum@a#1}% +\newcount\forest@isnum@count +\def\forest@isnum@p{% + \ifx0\forest@isnum@token + \let\forest@next\forest@isnum@next + \else + \let\forest@next\forest@isnum@nz@ + \fi + \forest@isnumtrue + \afterassignment\forest@isnum@q\forest@isnum@count\ifforest@isnum@minus-\fi0% +} +\def\forest@isnum@q{% + \futurelet\forest@isnum@token\forest@next +} +\def\forest@isnum@nz@{% + \ifnum\forest@isnum@count=0 + \forest@isnumfalse + \fi + \forest@isnum@next +} +\def\forest@isnum@finish#1\forest@END{% + \ifx\forest@isnum@token\forest@eon + \else + \forest@isnumfalse + \fi +} +\newcount\forest@isdim@nonintpart +\newif\ifforest@isdim +\def\forest@isdim#1{% + \forest@isdimfalse + \forest@isnum@minusfalse + \def\forest@isdim@leadingzeros{}% + \forest@isdim@nonintpart=0 + \def\forest@isdim@unit{pt}% + \let\forest@isnum@next\forest@isdim@checkfordot + \edef\forest@isnum@temp{#1}% + \expandafter\forest@isnum@a\forest@isnum@temp\forest@eon\forest@eon\forest@eon\forest@eon\forest@END + \ifforest@isdim + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi +} +\def\forest@isdim@checkfordot{% + \ifx.\forest@isnum@token + \expandafter\forest@isdim@dot + \else + \ifx,\forest@isnum@token + \expandafter\expandafter\expandafter\forest@isdim@dot + \else + \expandafter\expandafter\expandafter\forest@isdim@nodot + \fi + \fi +} +\def\forest@isdim@nodot{% + \ifforest@isnum + \expandafter\forest@isdim@checkforunit + \else + \expandafter\forest@isdim@finish@nodim + \fi +} +\def\forest@isdim@dot#1{% #1=. or , + \futurelet\forest@isnum@token\forest@isdim@collectzero +} +\def\forest@isdim@collectzero{% + \ifx0\forest@isnum@token + \expandafter\forest@isdim@collectzero@ + \else + \expandafter\forest@isdim@getnonintpart + \fi +} +\def\forest@isdim@collectzero@#1{% #1 = 0 + \appto\forest@isdim@leadingzeros{0}% + \futurelet\forest@isnum@token\forest@isdim@collectzero +} +\def\forest@isdim@getnonintpart{% + \afterassignment\forest@isdim@checkforunit\forest@isdim@nonintpart0% +} +\def\forest@def@unit#1{\csdef{forest@unit@#1}{#1}} +\forest@def@unit{em} +\forest@def@unit{ex} +\forest@def@unit{pt} +\forest@def@unit{pc} +\forest@def@unit{in} +\forest@def@unit{bp} +\forest@def@unit{cm} +\forest@def@unit{mm} +\forest@def@unit{dd} +\forest@def@unit{cc} +\forest@def@unit{sp} +\def\forest@isdim@checkforunit#1#2{% + \lowercase{\edef\forest@isnum@temp{\detokenize{#1#2}}}% + \ifcsname forest@unit@\forest@isnum@temp\endcsname + \let\forest@isdim@next\forest@isdim@finish@dim + \edef\forest@isdim@unit{\csname forest@unit@\forest@isnum@temp\endcsname}% + \else + \ifx#1\forest@eon + \let\forest@isdim@next\forest@isdim@finish@dim + \else + \let\forest@isdim@next\forest@isdim@finish@nodim + \fi + \fi + \forest@isdim@next +} +\def\forest@isdim@finish@dim{% + \futurelet\forest@isnum@token\forest@isdim@finish@dim@a +} +\def\forest@isdim@finish@dim@a{% + \expandafter\ifx\space\forest@isnum@token + \expandafter\forest@isdim@finish@dim@b + \else + \expandafter\forest@isdim@finish@dim@c + \fi +} +\expandafter\def\expandafter\forest@isdim@finish@dim@b\space{% eat one space + \futurelet\forest@isnum@token\forest@isdim@finish@dim@c +} +\def\forest@isdim@finish@dim@c#1\forest@END{% + \ifx\forest@isnum@token\forest@eon + \forest@isdimtrue + \forest@isdim@dimen\the\forest@isnum@count.\forest@isdim@leadingzeros\the\forest@isdim@nonintpart\forest@isdim@unit\relax + \else + \forest@isdimfalse + \fi +} +\def\forest@isdim@finish@nodim#1\forest@END{% + \forest@isdimfalse +} +\newdimen\forest@isdim@dimen + % \long\def\@firstofthree#1#2#3{#3} % defined by LaTeX +\long\def\@firstofthree#1#2#3{#1} +\long\def\@secondofthree#1#2#3{#2} +\def\forest@isnumdim#1{% + \forest@isdim{#1}{% + \forest@isnumdim@ + }{% + \@thirdofthree + }% +} +\def\forest@isnumdim@{% + \ifforest@isnum + \expandafter\@firstofthree + \else + \expandafter\@secondofthree + \fi +} +\def\forestmathtype@generic{_} % generic (token list) +\def\forestmathtype@count{n} % integer +\def\forestmathtype@dimen{d} % a dimension: <decimal> pt +\def\forestmathtype@unitless{P} % <decimal> (a unitless dimension) (P because pgfmath returns such numbers) +\def\forestmathtype@textasc{t} % text (ascending) +\def\forestmathtype@textdesc{T} % text (descending) +\def\forestmathtype@array{a} % array - internal +\def\forestmathtype@none{} % internal (for requests - means whatever) +\def\forestmathresult{} +\let\forestmathresulttype\forestmathtype@generic +\def\forest@tryprocess{% + \expandafter\forest@tryprocess@a\romannumeral-`0} +\def\forest@tryprocess@a{\futurelet\forest@temp@token\forest@tryprocess@b} +\def\forest@tryprocess@b{% + \ifx>\forest@temp@token + \expandafter\forest@tryprocess@yes + \else + \expandafter\forest@tryprocess@no + \fi +} +\def\forest@spacegen{ \forest@spacegen} +\def\forest@tryprocess@yes#1#2\forest@spacegen{% + \forest@process{false}#2\forest@eov + \@firstoftwo +} +\def\forest@tryprocess@no#1\forest@spacegen{\@secondoftwo} +\def\forestmathsetcount#1#2{% + \forest@tryprocess#2\forest@spacegen{% + #1=\forest@process@result\relax + }{% + \forestmathsetcount@#1{#2}% + }% +} +\def\forestmathsetcount@#1#2{% + \forest@isnum{#2}{% + #1=\forest@isnum@count + }{% + \pgfmathsetcount#1{#2}% + }% +} +\def\forestmathsetlength#1#2{% + \forest@tryprocess#2\forest@spacegen{% + #1=\forest@process@result\relax + }{% + \forestmathsetlength@#1{#2}% + }% +} +\def\forestmathsetlength@#1#2{% + \forest@isdim{#2}{% + #1=\forest@isdim@dimen + }{% + \pgfmathsetlength#1{#2}% + }% +} +\def\forestmathtruncatemacro#1#2{% + \forest@tryprocess#2\forest@spacegen{% + \forest@temp@count=\forest@process@result\relax + \edef#1{\the\forest@temp@count}% + }{% + \forestmathtruncatemacro@#1{#2}% + }% +} +\def\forestmathtruncatemacro@#1#2{% + \forest@isnum{#2}{% + \edef#1{\the\forest@isnum@count}% + }{% + \pgfmathtruncatemacro#1{#2}% + }% +} +\def\forestmathsetlengthmacro#1#2{% + \forest@tryprocess#2\forest@spacegen{% + \forest@temp@dimen=\forest@process@result\relax + \edef#1{\the\forest@temp@dimen}% + }{% + \forestmathsetlengthmacro@#1{#2}% + }% +} +\def\forestmathsetlengthmacro@#1#2{% + \forest@isdim{#2}{% + \edef#1{\the\forest@isdim@dimen}% + }{% + \pgfmathsetlengthmacro#1{#2}% + }% +} +\def\forestmathsetmacro#1#2{% + \forest@tryprocess#2\forest@spacegen{% + \let#1\forest@process@result + \let\forestmathresulttype\forest@process@result@type + }{% + \forestmathsetmacro@#1{#2}% + \def\forestmathresulttype{P}% + }% +} +\def\forestmathsetmacro@#1#2{% + \forest@isdim{#2}{% + \edef#1{\expandafter\Pgf@geT\the\forest@isdim@dimen}% + }{% + \pgfmathsetmacro#1{#2}% + }% +} +\def\forestmathparse#1{% + \forest@tryprocess#1\forest@spacegen{% + \let\forestmathresult\forest@process@result + \let\forestmathresulttype\forest@process@result@type + }{% + \forestmathparse@{#1}% + \def\forestmathresulttype{P}% + }% +} +\def\forestmathparse@#1{% + \forest@isdim{#1}{% + \edef\forestmathresult{\expandafter\Pgf@geT\the\forest@isdim@dimen}% + }{% + \pgfmathsetmacro\forestmathresult{#1}% + }% +} +\csdef{forest@bh@0}{0} +\csdef{forest@bh@false}{0} +\csdef{forest@bh@1}{1} +\csdef{forest@bh@true}{1} +\def\forestmath@if#1{% + \ifcsdef{forest@bh@\detokenize{#1}}{% + \let\forest@next\forestmath@if@fast + }{% + \let\forest@next\forestmath@if@slow + }% + \forest@next{#1}% + \ifnum\forest@temp=0 + \expandafter\@secondoftwo + \else + \expandafter\@firstoftwo + \fi +} +\def\forestmath@if@fast#1{\letcs\forest@temp{forest@bh@\detokenize{#1}}} +\def\forestmath@if@slow#1{\forestmathtruncatemacro\forest@temp{#1}} +\def\forestmath@convert@fromto#1#2#3{% + \edef\forestmathresult{\csname forestmath@convert@from@#1@to@#2\endcsname{#3}}} +\def\forestmath@convert@from#1{\forestmath@convert@fromto{#1}{\forestmathresulttype}} +\def\forestmath@convert@to{\forestmath@convert@fromto{\forestmathresulttype}} +\def\forestmath@convert@from@n@to@n#1{#1} +\def\forestmath@convert@from@n@to@d#1{#1\pgfmath@pt} +\def\forestmath@convert@from@n@to@P#1{#1} +\def\forestmath@convert@from@d@to@n#1{% + \expandafter\forestmath@convert@uptodot\Pgf@geT#1.\forest@eov} +\def\forestmath@convert@from@d@to@d#1{#1} +\def\forestmath@convert@from@d@to@P#1{\Pgf@geT#1} +\def\forestmath@convert@from@P@to@n#1{% + \forestmath@convert@uptodot#1.\forest@eov} +\def\forestmath@convert@from@P@to@d#1{#1\pgfmath@pt} +\def\forestmath@convert@from@P@to@P#1{#1} +\def\forestmath@convert@uptodot#1.#2\forest@eov{#1} +\def\forestmathzero{\forestmath@convert@from\forestmathtype@count{0}} +\csdef{forestmath@convert@from@n@to@_}#1{\unexpanded{#1}} +\csdef{forestmath@convert@from@d@to@_}#1{\unexpanded{#1}} +\csdef{forestmath@convert@from@P@to@_}#1{\unexpanded{#1}} +\def\forestmathsettypefrom#1{% + \forest@isnumdim{% + \let\forestmathresulttype\forest@result@type@numexpr + }{% + \let\forestmathresulttype\forest@result@type@dimexpr + }{% + \let\forestmathresulttype\forest@result@type@pgfmath + }% +} +\def\forestmathadd#1#2{\edef\forestmathresult{% + \csname forestmathadd@\forestmathresulttype\endcsname{#1}{#2}}} +\def\forestmathadd@#1#2#3{\edef\forestmathresult{% + \csname forestmathadd@#1\endcsname{#2}{#3}}} +\def\forestmathadd@n#1#2{\the\numexpr#1+#2\relax} +\def\forestmathadd@d#1#2{\the\dimexpr#1+#2\relax} +\def\forestmathadd@P#1#2{\expandafter\Pgf@geT\the\dimexpr#1pt+#2pt\relax} +\def\forestmathmultiply#1#2{% + \csname forestmathmultiply@\forestmathresulttype\endcsname{#1}{#2}} +\def\forestmathmultiply@#1#2#3{% + \csname forestmathmultiply@#1\endcsname{#2}{#3}} +\def\forestmathmultiply@n#1#2{\edef\forestmathresult{% + \the\numexpr#1*#2\relax}} +\def\forestmathmultiply@d#1#2{% + \edef\forestmath@marshal{\forestmathmultiply@d@{#1}{#2}}\forestmath@marshal +} +\def\forestmathmultiply@d@#1#2{% + \edef\forestmath@marshal{% + \noexpand\pgfmathmultiply@{\Pgf@geT#1}{\Pgf@geT#2}% + }\forestmath@marshal + \edef\forestmathresult{\pgfmathresult\pgfmath@pt}% +} +\def\forestmathmultiply@P#1#2{% + \pgfmathmultiply@{#1}{#2}% + \let\forestmathresult\pgfmathresult +} +\def\forestmathdivide#1#2{% + \csname forestmathdivide@\forestmathresulttype\endcsname{#1}{#2}} +\def\forestmathdivide@#1#2#3{% + \csname forestmathdivide@#1\endcsname{#2}{#3}} +\def\forestmathdivide@n#1#2{\edef\forestmathresult{% + \the\numexpr#1/#2\relax}} +\def\forestmathdivide@d#1#2{\edef\forestmathresult{% + \the\dimexpr#1/#2\relax}} +\def\forestmathdivide@P#1#2{% + \edef\forest@marshal{% + \noexpand\pgfmathdivide{+#1}{+#2}% + }\forest@marshal + \let\forestmathresult\pgfmathresult +} +\def\forestmathtrue{% + \def\forestmathresult{1}% + \let\forestmathresulttype\forestmathtype@count} +\def\forestmathfalse{% + \def\forestmathresult{0}% + \let\forestmathresulttype\forestmathtype@count} +\def\forestmath@if@lt@n#1#2{\ifnum#1<#2\relax + \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi} +\def\forestmath@if@lt@d#1#2{\ifdim#1<#2\relax + \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi} +\def\forestmath@if@lt@P#1#2{\ifdim#1pt<#2pt + \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi} +\def\forestmath@if@lt@t#1#2{\ifnum\pdfstrcmp{#1}{#2}<0 + \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi} +\def\forestmath@if@lt@T#1#2{\ifnum\pdfstrcmp{#1}{#2}>0 + \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi} +\def\forest@cmp@error#1#2{\PackageError{forest}{Comparison + ("<" or ">") of generic type arguments "#1" and "#2" + makes no sense}{Use one of argument processor instructions + "n", "d", "P" or "t" to change the type. Use package option + "debug=process" to see what's happening here.}} +\cslet{forestmath@if@lt@_}\forest@cmp@error +\def\forestmath@if@eq@n#1#2{\ifnum#1=#2\relax + \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi} +\def\forestmath@if@eq@d#1#2{\ifdim#1=#2\relax + \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi} +\def\forestmath@if@eq@P#1#2{\ifdim#1pt=#2pt + \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi} +\def\forestmath@if@eq@t#1#2{\ifnum\pdfstrcmp{#1}{#2}=0 + \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi} +\let\forestmath@if@eq@T\forestmath@if@eq@t +\csdef{forestmath@if@eq@_}#1#2{% + \def\forestmath@tempa{#1}% + \def\forestmath@tempb{#2}% + \ifx\forestmath@tempa\forestmath@tempb + \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi} +\def\forestmathlt#1#2{% + \csname forestmath@if@lt@\forestmathresulttype\endcsname{#1}{#2}% + \forestmathtrue + \forestmathfalse} +\def\forestmathlt@#1#2#3{% + \csname forestmath@if@lt@#1\endcsname{#2}{#3}% + \forestmathtrue + \forestmathfalse} +\def\forestmathgt#1#2{% + \csname forestmath@if@lt@\forestmathresulttype\endcsname{#2}{#1}% + \forestmathtrue + \forestmathfalse} +\def\forestmathgt@#1#2#3{% + \csname forestmath@if@lt@#1\endcsname{#3}{#2}% + \forestmathtrue + \forestmathfalse} +\def\forestmatheq#1#2{% + \csname forestmath@if@eq@\forestmathresulttype\endcsname{#1}{#2}% + \forestmathtrue + \forestmathfalse} +\def\forestmatheq@#1#2#3{% + \csname forestmath@if@eq@#1\endcsname{#2}{#3}% + \forestmathtrue + \forestmathfalse} +\def\forestmathmin{\forestmath@minmax{min}{\forestmathresulttype}} +\def\forestmathmax{\forestmath@minmax{max}{\forestmathresulttype}} +\def\forestmathmin@{\forestmath@minmax{min}} +\def\forestmathmax@{\forestmath@minmax{max}} +\def\forestmath@minmax#1#2#3#4{% #1=min/max, #2=type, #3,#4=args + \edef\forestmath@tempa{#3}% + \edef\forestmath@tempb{#4}% + \if\relax\detokenize\expandafter{\forestmath@tempa}\relax + \forestmath@minmax@one{#1}{#2}\forestmath@tempb + \else + \if\relax\detokenize\expandafter{\forestmath@tempb}\relax + \forestmath@minmax@one{#1}{#2}\forestmath@tempa + \else + \csname forestmath@#1\endcsname{#2}% + \fi + \fi +} +\def\forestmath@minmax@one#1#2#3{% #1=min/max, #2=type, #3 = the (possibly) non-empty arg + \ifcsname forestmath@#1@one@#2\endcsname + \csname forestmath@#1@one@#2\endcsname#3% + \else + \let\forestmathresult#3% + \fi +} +\def\forestmath@min@one@t#1{\let\forestmathresult\forest@empty} +\def\forestmath@max@one@t#1{\let\forestmathresult#1} +\def\forestmath@min@one@T#1{\let\forestmathresult#1} +\def\forestmath@max@one@T#1{\let\forestmathresult\forest@empty} + +\def\forestmath@min#1{% #1 = type + \csname forestmath@if@lt@#1\endcsname\forestmath@tempa\forestmath@tempb + {\let\forestmathresult\forestmath@tempa}% + {\let\forestmathresult\forestmath@tempb}% +} +\def\forestmath@max#1{% #1 = type + \csname forestmath@if@lt@#1\endcsname\forestmath@tempa\forestmath@tempb + {\let\forestmathresult\forestmath@tempb}% + {\let\forestmathresult\forestmath@tempa}% +} \def\forest@sort#1#2#3#4#5{% \let\forest@sort@cmp#1\relax \let\forest@sort@let#2\relax @@ -869,51 +1648,37 @@ \bracket@afterthought={}% } % full expansion expands precisely to the value -\def\forestov#1{\expandafter\expandafter\expandafter\expandonce - \pgfkeysvalueof{/forest/@node/\forest@cn/#1}} +\def\forestov#1{\expandafter\expandonce\csname fRsT\forest@cn/#1\endcsname} % full expansion expands all the way -\def\forestove#1{\pgfkeysvalueof{/forest/@node/\forest@cn/#1}} +\def\forestove#1{\csname fRsT\forest@cn/#1\endcsname} % full expansion expands to the cs holding the value -\def\forestom#1{\expandafter\expandonce\expandafter{\pgfkeysvalueof{/forest/@node/\forest@cn/#1}}} -\def\forestoget#1#2{\pgfkeysgetvalue{/forest/@node/\forest@cn/#1}{#2}} -\def\forestolet#1#2{\pgfkeyslet{/forest/@node/\forest@cn/#1}{#2}} -\def\forestocslet#1#2{% - \edef\forest@marshal{% - \noexpand\pgfkeyslet{/forest/@node/\forest@cn/#1}{\expandonce{\csname#2\endcsname}}% - }\forest@marshal -} -\def\forestoset#1#2{\pgfkeyssetvalue{/forest/@node/\forest@cn/#1}{#2}} -\def\forestoeset#1#2{% - \edef\forest@option@temp{% - \noexpand\pgfkeyssetvalue{/forest/@node/\forest@cn/#1}{#2}% - }\forest@option@temp -} +\def\forestom#1{\expandonce{\csname fRsT\forest@cn/#1\endcsname}} +\def\forestoget#1#2{\expandafter\let\expandafter#2\csname fRsT\forest@cn/#1\endcsname} +\def\forestolet#1#2{\expandafter\let\csname fRsT\forest@cn/#1\endcsname#2} +\def\forestoset#1#2{\expandafter\edef\csname fRsT\forest@cn/#1\endcsname{\unexpanded{#2}}} +\def\forestoeset#1%#2 + {\expandafter\edef\csname fRsT\forest@cn/#1\endcsname + %{#2} + } \def\forestoappto#1#2{% \forestoeset{#1}{\forestov{#1}\unexpanded{#2}}% } -\def\forestoifdefined#1#2#3{% - \pgfkeysifdefined{/forest/@node/\forest@cn/#1}{#2}{#3}% +\def\forestoifdefined#1%#2#3 +{% + \ifcsdef{fRsT\forest@cn/#1}%{#2}{#3}% } \let\forestoption\forestov \let\foresteoption\forestove -\def\forestOv#1#2{\expandafter\expandafter\expandafter\expandonce - \pgfkeysvalueof{/forest/@node/#1/#2}} -\def\forestOve#1#2{\pgfkeysvalueof{/forest/@node/#1/#2}} +\def\forestOv#1#2{\expandafter\expandonce\csname fRsT#1/#2\endcsname} +\def\forestOve#1#2{\csname fRsT#1/#2\endcsname} % full expansion expands to the cs holding the value -\def\forestOm#1#2{\expandafter\expandonce\expandafter{\pgfkeysvalueof{/forest/@node/#1/#2}}} -\def\forestOget#1#2#3{\pgfkeysgetvalue{/forest/@node/#1/#2}{#3}} -\def\forestOget#1#2#3{\pgfkeysgetvalue{/forest/@node/#1/#2}{#3}} -\def\forestOlet#1#2#3{\pgfkeyslet{/forest/@node/#1/#2}{#3}} -\def\forestOcslet#1#2#3{% - \edef\forest@marshal{% - \noexpand\pgfkeyslet{/forest/@node/#1/#2}{\expandonce{\csname#3\endcsname}}% - }\forest@marshal -} -\def\forestOset#1#2#3{\pgfkeyssetvalue{/forest/@node/#1/#2}{#3}} -\def\forestOeset#1#2#3{% - \edef\forestoption@temp{% - \noexpand\pgfkeyssetvalue{/forest/@node/#1/#2}{#3}% - }\forestoption@temp +\def\forestOm#1#2{\expandonce{\csname fRsT#1/#2\endcsname}} +\def\forestOget#1#2#3{\expandafter\let\expandafter#3\csname fRsT#1/#2\endcsname} +\def\forestOlet#1#2#3{\expandafter\let\csname fRsT#1/#2\endcsname#3} +\def\forestOset#1#2#3{\expandafter\edef\csname fRsT#1/#2\endcsname{\unexpanded{#3}}} +\def\forestOeset#1#2%#3 +{\expandafter\edef\csname fRsT#1/#2\endcsname + % {#3} } \def\forestOappto#1#2#3{% \forestOeset{#1}{#2}{\forestOv{#1}{#2}\unexpanded{#3}}% @@ -927,8 +1692,9 @@ \def\forestOepreto#1#2#3{% \forestOeset{#1}{#2}{#3\forestOv{#1}{#2}}% } -\def\forestOifdefined#1#2#3#4{% - \pgfkeysifdefined{/forest/@node/#1/#2}{#3}{#4}% +\def\forestOifdefined#1#2%#3#4 +{% + \ifcsdef{fRsT#1/#2}%{#3}{#4}% } \def\forestOletO#1#2#3#4{% option #2 of node #1 <-- option #4 of node #3 \forestOget{#3}{#4}\forestoption@temp @@ -942,34 +1708,57 @@ \def\forestoleto#1#2{% \forestoget{#2}\forestoption@temp \forestolet{#1}\forestoption@temp} +\def\forestRNOget#1#2{% #1=rn!option, #2 = receiving cs + \pgfutil@in@{.}{#1}% + \ifpgfutil@in@ + \forestRNOget@rn#2#1\forest@END + \else + \forestoget{#1}#2% + \fi +} +\def\forestRNOget@rn#1#2.#3\forest@END{% + \forest@forthis{% + \forest@nameandgo{#2}% + \forestoget{#3}#1% + }% +} +\def\forestRNO@getvalueandtype#1#2#3{% #1=rn.option, #2,#3 = receiving css + \pgfutil@in@{.}{#1}% + \ifpgfutil@in@ + \forestRNO@getvalueandtype@rn#2#3#1\forest@END + \else + \forestoget{#1}#2% + \pgfkeysgetvalue{/forest/#1/@type}#3% + \fi +} +\def\forestRNO@getvalueandtype@rn#1#2#3.#4\forest@END{% + % #1,#2=receiving css, #3=relative node name, #4=option name + \forest@forthis{% + \forest@nameandgo{#3}% + \forestoget{#4}#1% + }% + \pgfkeysgetvalue{/forest/#4/@type}#2% +} % full expansion expands precisely to the value -\def\forestrv#1{\expandafter\expandafter\expandafter\expandonce - \pgfkeysvalueof{/forest/@node/register/#1}} +\def\forestrv#1{\expandafter\expandonce\csname fRsT/#1\endcsname} % full expansion expands all the way -\def\forestrve#1{\pgfkeysvalueof{/forest/@node/register/#1}} +\def\forestrve#1{\csname fRsT/#1\endcsname} % full expansion expands to the cs holding the value -\def\forestrm#1{\expandafter\expandonce\expandafter{\pgfkeysvalueof{/forest/@node/register/#1}}} -\def\forestrget#1#2{\pgfkeysgetvalue{/forest/@node/register/#1}{#2}} -\def\forestrlet#1#2{\pgfkeyslet{/forest/@node/register/#1}{#2}} -\def\forestrcslet#1#2{% - \edef\forest@marshal{% - \noexpand\pgfkeyslet{/forest/@node/register/#1}{\expandonce{\csname#2\endcsname}}% - }\forest@marshal -} -\def\forestrset#1#2{\pgfkeyssetvalue{/forest/@node/register/#1}{#2}} -\def\forestreset#1#2{% - \edef\forest@option@temp{% - \noexpand\pgfkeyssetvalue{/forest/@node/register/#1}{#2}% - }\forest@option@temp -} +\def\forestrm#1{\expandonce{\csname fRsT/#1\endcsname}} +\def\forestrget#1#2{\expandafter\let\expandafter#2\csname fRsT/#1\endcsname} +\def\forestrlet#1#2{\expandafter\let\csname fRsT/#1\endcsname#2} +\def\forestrset#1#2{\expandafter\edef\csname fRsT/#1\endcsname{\unexpanded{#2}}} +\def\forestreset#1%#2 + {\expandafter\edef\csname fRsT/#1\endcsname}%{#2} \def\forestrappto#1#2{% \forestreset{#1}{\forestrv{#1}\unexpanded{#2}}% } \def\forestrpreto#1#2{% \forestreset{#1}{\unexpanded{#2}\forestrv{#1}}% } -\def\forestrifdefined#1#2#3{% - \pgfkeysifdefined{/forest/@node/register/#1}{#2}{#3}% +\def\forestrifdefined#1%#2#3 +{% + \ifcsdef{fRsT/#1}%{#2}{#3}% } \def\forestregister#1{\forestrv{#1}} \def\foresteregister#1{\forestrve{#1}} @@ -1498,7 +2287,12 @@ } \NewDocumentCommand\forestdebugtypeouttrees{o}{% \forestdebug@typeouttrees\forest@temp - \typeout{\IfValueTF{#1}{#1: }{}\forest@temp}% + \typeout{% + \forestdebugtypeouttreesprefix + \IfValueTF{#1}{#1: }{}% + \detokenize\expandafter{\forest@temp}% + \forestdebugtypeouttreessuffix + }% } \def\forestdebug@typeouttrees#1{% #1 = cs to store the result \begingroup @@ -1514,12 +2308,12 @@ \expandafter\endgroup \expandafter\edef\expandafter\forest@cn\expandafter{\forest@cn}% \forestdebug@typeouttree@build - \appto\forest@temp@message{\space}% + \appto\forest@temp@message{ }% }% }% \repeat \expandafter\endgroup - \expandafter\edef\expandafter#1\expandafter{\forest@temp@message}% + \expandafter\def\expandafter#1\expandafter{\forest@temp@message}% } \def\forestdebug@typeouttrees@findroot{% \let\forestdebug@typeouttrees@next\relax @@ -1546,9 +2340,9 @@ \typeout{\IfValueTF{#1}{#1: }{}\forest@temp}% } \def\forestdebug@typeouttree@build{% - \eappto\forest@temp@message{[\forest@cn%] + \eappto\forest@temp@message{[\forestdebugtypeouttreenodeinfo%] \ifcsdef{forestdebug@typeouttree@used@\forest@cn}{*}{}% - }% + }% \ifcsdef{forestdebug@typeouttree@used@\forest@cn}{}{% \csdef{forestdebug@typeouttree@used@\forest@cn}{}% \forest@node@foreachchild{\forestdebug@typeouttree@build}% @@ -1556,6 +2350,9 @@ \eappto\forest@temp@message{%[ ]}% } +\def\forestdebugtypeouttreenodeinfo{\forest@cn} +\def\forestdebugtypeouttreesprefix{} +\def\forestdebugtypeouttreessuffix{} \def\forest@declarehandler#1#2#3{%#1=handler for specific type,#2=option name,#3=default value \pgfkeyssetvalue{/forest/#2}{#3}% \appto\forest@node@init{\forestoinit{#2}}% @@ -1635,6 +2432,7 @@ \pgfkeyssetvalue{#1/option@name}{#3}% \pgfkeyssetvalue{#1+/option@name}{#3}% \pgfkeyssetvalue{#2/+#3/option@name}{#3}% + \pgfkeyslet{#1/@type}\forestmathtype@generic % for .process & co \pgfmathdeclarefunction{#4}{1}{\forest@pgfmathhelper@attribute@toks{##1}{#3}}% } \def\forest@declareautowrappedtoks@handler#1#2#3#4{% #1=key,#2=path,#3=name,#4=pgfmathname,#5=infix @@ -1664,25 +2462,44 @@ \pgfkeysalso{##3}% \fi }, + #2/if #3</.code n args={3}{% + \forestoget{#3}\forest@temp@option@value + \ifdim\forest@temp@option@value>##1\relax + \pgfkeysalso{##3}% + \else + \pgfkeysalso{##2}% + \fi + }, + #2/if #3>/.code n args={3}{% + \forestoget{#3}\forest@temp@option@value + \ifdim\forest@temp@option@value<##1\relax + \pgfkeysalso{##3}% + \else + \pgfkeysalso{##2}% + \fi + }, #2/where #3/.style n args={3}{for tree={#2/if #3={##1}{##2}{##3}}}, + #2/where #3</.style n args={3}{for tree={#2/if #3<={##1}{##2}{##3}}}, + #2/where #3>/.style n args={3}{for tree={#2/if #3>={##1}{##2}{##3}}}, }% + \pgfkeyslet{#1/@type}\forestmathtype@dimen % for .process & co \pgfmathdeclarefunction{#4}{1}{\forest@pgfmathhelper@attribute@dimen{##1}{#3}}% } \def\forest@declaredimen@handler#1#2#3#4{% #1=key,#2=path,#3=name,#4=pgfmathname \forest@declarereadonlydimen@handler{#1}{#2}{#3}{#4}% \pgfkeysalso{% #1/.code={% - \pgfmathsetlengthmacro\forest@temp{##1}% + \forestmathsetlengthmacro\forest@temp{##1}% \forestOlet{\forest@setter@node}{#3}\forest@temp }, #1+/.code={% - \pgfmathsetlengthmacro\forest@temp{##1}% + \forestmathsetlengthmacro\forest@temp{##1}% \pgfutil@tempdima=\forestove{#3} \advance\pgfutil@tempdima\forest@temp\relax \forestOeset{\forest@setter@node}{#3}{\the\pgfutil@tempdima}% }, #1-/.code={% - \pgfmathsetlengthmacro\forest@temp{##1}% + \forestmathsetlengthmacro\forest@temp{##1}% \pgfutil@tempdima=\forestove{#3} \advance\pgfutil@tempdima-\forest@temp\relax \forestOeset{\forest@setter@node}{#3}{\the\pgfutil@tempdima}% @@ -1739,37 +2556,56 @@ \pgfkeysalso{##3}% \fi }, + #2/if #3</.code n args={3}{% + \forestoget{#3}\forest@temp@option@value + \ifnum\forest@temp@option@value>##1\relax + \pgfkeysalso{##3}% + \else + \pgfkeysalso{##2}% + \fi + }, + #2/if #3>/.code n args={3}{% + \forestoget{#3}\forest@temp@option@value + \ifnum\forest@temp@option@value<##1\relax + \pgfkeysalso{##3}% + \else + \pgfkeysalso{##2}% + \fi + }, #2/where #3/.style n args={3}{for tree={#2/if #3={##1}{##2}{##3}}}, + #2/where #3</.style n args={3}{for tree={#2/if #3<={##1}{##2}{##3}}}, + #2/where #3>/.style n args={3}{for tree={#2/if #3>={##1}{##2}{##3}}}, }% + \pgfkeyslet{#1/@type}\forestmathtype@count % for .process & co \pgfmathdeclarefunction{#4}{1}{\forest@pgfmathhelper@attribute@count{##1}{#3}}% } \def\forest@declarecount@handler#1#2#3#4{% #1=key,#2=path,#3=name,#4=pgfmathname \forest@declarereadonlycount@handler{#1}{#2}{#3}{#4}% \pgfkeysalso{ #1/.code={% - \pgfmathtruncatemacro\forest@temp{##1}% + \forestmathtruncatemacro\forest@temp{##1}% \forestOlet{\forest@setter@node}{#3}\forest@temp }, #1+/.code={% - \pgfmathtruncatemacro\forest@temp{##1}% + \forestmathtruncatemacro\forest@temp{##1}% \c@pgf@counta=\forestove{#3}\relax \advance\c@pgf@counta\forest@temp\relax \forestOeset{\forest@setter@node}{#3}{\the\c@pgf@counta}% }, #1-/.code={% - \pgfmathtruncatemacro\forest@temp{##1}% + \forestmathtruncatemacro\forest@temp{##1}% \c@pgf@counta=\forestove{#3}\relax \advance\c@pgf@counta-\forest@temp\relax \forestOeset{\forest@setter@node}{#3}{\the\c@pgf@counta}% }, #1*/.code={% - \pgfmathtruncatemacro\forest@temp{##1}% + \forestmathtruncatemacro\forest@temp{##1}% \c@pgf@counta=\forestove{#3}\relax \multiply\c@pgf@counta\forest@temp\relax \forestOeset{\forest@setter@node}{#3}{\the\c@pgf@counta}% }, #1:/.code={% - \pgfmathtruncatemacro\forest@temp{##1}% + \forestmathtruncatemacro\forest@temp{##1}% \c@pgf@counta=\forestove{#3}\relax \divide\c@pgf@counta\forest@temp\relax \forestOeset{\forest@setter@node}{#3}{\the\c@pgf@counta}% @@ -1813,30 +2649,27 @@ \def\forest@declareboolean@handler#1#2#3#4{% #1=key,#2=path,#3=name,#4=pgfmathname \pgfkeysalso{% #1/.code={% - \ifstrequal{##1}{1}{% - \forestOset{\forest@setter@node}{#3}{1}% + \forestmath@if{##1}{% + \def\forest@temp{1}% }{% - \ifstrequal{##1}{0}{% - \forestOset{\forest@setter@node}{#3}{0}% - }{% - \pgfmathifthenelse{##1}{1}{0}% - \forestOlet{\forest@setter@node}{#3}\pgfmathresult - }% + \def\forest@temp{0}% }% + \forestOlet{\forest@setter@node}{#3}\forest@temp }, #1/.default=1, #2/not #3/.code={\forestOset{\forest@setter@node}{#3}{0}}, #2/if #3/.code 2 args={% \forestoget{#3}\forest@temp@option@value - \ifnum\forest@temp@option@value=1 - \pgfkeysalso{##1}% - \else + \ifnum\forest@temp@option@value=0 \pgfkeysalso{##2}% + \else + \pgfkeysalso{##1}% \fi }, #2/where #3/.style 2 args={for tree={#2/if #3={##1}{##2}}} }% \pgfkeyssetvalue{#1/option@name}{#3}% + \pgfkeyslet{#1/@type}\forestmathtype@count % for .process & co \pgfmathdeclarefunction{#4}{1}{\forest@pgfmathhelper@attribute@count{##1}{#3}}% } \forestset{ @@ -1850,31 +2683,35 @@ \forest@declarehandler\forest@declarekeylist@handler{#1}{#2}% }, declare readonly dimen/.code 2 args={% - \pgfmathsetlengthmacro\forest@temp{#2}% + \forestmathsetlengthmacro\forest@temp{#2}% \edef\forest@marshal{% \unexpanded{\forest@declarehandler\forest@declarereadonlydimen@handler{#1}}{\forest@temp}% }\forest@marshal }, declare dimen/.code 2 args={% - \pgfmathsetlengthmacro\forest@temp{#2}% + \forestmathsetlengthmacro\forest@temp{#2}% \edef\forest@marshal{% \unexpanded{\forest@declarehandler\forest@declaredimen@handler{#1}}{\forest@temp}% }\forest@marshal }, declare readonly count/.code 2 args={% - \pgfmathtruncatemacro\forest@temp{#2}% + \forestmathtruncatemacro\forest@temp{#2}% \edef\forest@marshal{% \unexpanded{\forest@declarehandler\forest@declarereadonlycount@handler{#1}}{\forest@temp}% }\forest@marshal }, declare count/.code 2 args={% - \pgfmathtruncatemacro\forest@temp{#2}% + \forestmathtruncatemacro\forest@temp{#2}% \edef\forest@marshal{% \unexpanded{\forest@declarehandler\forest@declarecount@handler{#1}}{\forest@temp}% }\forest@marshal }, declare boolean/.code 2 args={% - \pgfmathtruncatemacro\forest@temp{#2}% + \forestmath@if{#2}{% + \def\forest@temp{1}% + }{% + \def\forest@temp{0}% + }% \edef\forest@marshal{% \unexpanded{\forest@declarehandler\forest@declareboolean@handler{#1}}{\forest@temp}% }\forest@marshal @@ -1898,17 +2735,22 @@ \pgfkeysalso{\forest@handlers@wrap@currentpath/.expand once=\forest@wrapped@value}% }, /handlers/.option/.code={% - \edef\forest@marshal{% - \noexpand\pgfkeysalso{\pgfkeyscurrentpath={\forestoption{#1}}}% - }\forest@marshal + \edef\forest@temp{\pgfkeyscurrentpath}% + \expandafter\forest@handlers@option\expandafter{\forest@temp}{#1}% }, +} +\def\forest@handlers@option#1#2{%#1=pgfkeyscurrentpath,#2=relative node name + \forestRNOget{#2}\forest@temp + \pgfkeysalso{#1/.expand once={\forest@temp}}% +}% +\forestset{ /handlers/.register/.code={% \edef\forest@marshal{% \noexpand\pgfkeysalso{\pgfkeyscurrentpath={\forestregister{#1}}}% }\forest@marshal }, /handlers/.wrap pgfmath arg/.code 2 args={% - \pgfmathparse{#2}\let\forest@wrap@arg@i\pgfmathresult + \forestmathparse{#2}\let\forest@wrap@arg@i\forestmathresult \edef\forest@wrap@args{{\expandonce\forest@wrap@arg@i}}% \def\forest@wrap@code##1{#1}% % here we don't call \forest@wrap@pgfmath@args@@@wrapandpasson, as compat-2.0.2-wrappgfmathargs changes that to achieve the old, confusing state of affairs, which *didn't* apply at *1*-arg pgfmath wrapping @@ -1916,8 +2758,8 @@ \expandafter\pgfkeysalso\expandafter{\expandafter\pgfkeyscurrentpath\expandafter=\expandafter{\the\forest@temp@toks}}% }, /handlers/.wrap 2 pgfmath args/.code n args={3}{% - \pgfmathparse{#2}\let\forest@wrap@arg@i\pgfmathresult - \pgfmathparse{#3}\let\forest@wrap@arg@ii\pgfmathresult + \forestmathparse{#2}\let\forest@wrap@arg@i\forestmathresult + \forestmathparse{#3}\let\forest@wrap@arg@ii\forestmathresult \edef\forest@wrap@args{{\expandonce\forest@wrap@arg@i}{\expandonce\forest@wrap@arg@ii}}% \def\forest@wrap@code##1##2{#1}% \forest@wrap@pgfmath@args@@@wrapandpasson @@ -1940,19 +2782,16 @@ /handlers/.wrap 8 pgfmath args/.code n args={9}{% \forest@wrap@n@pgfmath@args{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}{8}% \forest@wrap@n@pgfmath@do{#1}{8}}, - /handlers/.process args/.code={% - \forest@processargs#1\forest@eov\forest@END - }, } \def\forest@wrap@n@pgfmath@args#1#2#3#4#5#6#7#8#9{% - \pgfmathparse{#1}\let\forest@wrap@arg@i\pgfmathresult - \ifnum#9>1 \pgfmathparse{#2}\let\forest@wrap@arg@ii\pgfmathresult\fi - \ifnum#9>2 \pgfmathparse{#3}\let\forest@wrap@arg@iii\pgfmathresult\fi - \ifnum#9>3 \pgfmathparse{#4}\let\forest@wrap@arg@iv\pgfmathresult\fi - \ifnum#9>4 \pgfmathparse{#5}\let\forest@wrap@arg@v\pgfmathresult\fi - \ifnum#9>5 \pgfmathparse{#6}\let\forest@wrap@arg@vi\pgfmathresult\fi - \ifnum#9>6 \pgfmathparse{#7}\let\forest@wrap@arg@vii\pgfmathresult\fi - \ifnum#9>7 \pgfmathparse{#8}\let\forest@wrap@arg@viii\pgfmathresult\fi + \forestmathparse{#1}\let\forest@wrap@arg@i\forestmathresult + \ifnum#9>1 \forestmathparse{#2}\let\forest@wrap@arg@ii\forestmathresult\fi + \ifnum#9>2 \forestmathparse{#3}\let\forest@wrap@arg@iii\forestmathresult\fi + \ifnum#9>3 \forestmathparse{#4}\let\forest@wrap@arg@iv\forestmathresult\fi + \ifnum#9>4 \forestmathparse{#5}\let\forest@wrap@arg@v\forestmathresult\fi + \ifnum#9>5 \forestmathparse{#6}\let\forest@wrap@arg@vi\forestmathresult\fi + \ifnum#9>6 \forestmathparse{#7}\let\forest@wrap@arg@vii\forestmathresult\fi + \ifnum#9>7 \forestmathparse{#8}\let\forest@wrap@arg@viii\forestmathresult\fi \edef\forest@wrap@args{% {\expandonce\forest@wrap@arg@i} \ifnum#9>1 {\expandonce\forest@wrap@arg@ii}\fi @@ -1985,117 +2824,498 @@ \expandafter\pgfkeyscurrentpath\expandafter=\expandafter{% \the\forest@temp@toks}}% } -\newtoks\forest@processargs@result -\newtoks\forest@processargs@current -\newif\ifforest@processargs@append -\def\forest@eov{\forest@eov} -\def\forest@processargs#1#2\forest@END{% #1 = processing instructions, #2 = args - \forest@processargs@result{}% - \forest@processargs@current{}% - \forest@processargs@appendfalse - \forest@processargs@getins#1.\forest@END#2\forest@END -} -\def\forest@processargs@maybeappend{% - \ifforest@processargs@append - \eapptotoks\forest@processargs@result{{\the\forest@processargs@current}}% - \forest@processargs@current{}% - \fi -} -\def\forest@processargs@getins#1#2\forest@END#3\forest@END{% #1 = first instruction, #2 = rest of instructions, #3 = args - \csname forest@processargs@ins@#1\endcsname#2\forest@END#3\forest@END -} -\csdef{forest@processargs@ins@.}\forest@END#1\forest@END{% - \forest@processargs@maybeappend - \forest@processargs@appremainingargs#1\forest@END -} -\def\forest@processargs@appremainingargs#1#2\forest@END{% - \edef\forest@temp{\unexpanded{#1}}% - \ifx\forest@temp\forest@eov - \let\forest@processargs@next\forest@processargs@done +\def\forest@process@catregime{} % filled by processor defs +\forest@newarray\forest@process@left@ % processed args +\forest@newarray\forest@process@right@ % unprocessed args +\forest@newarray\forest@process@saved@ % used by instructions |S| and |U| +\let\forest@process@savedtype\forestmathtype@none +\forest@newglobalarray\forest@process@result@ +\newif\ifforest@process@returnarray@ +\def\forest@process#1#2#{% #1 = true/false (should we return an array?) + % #2 = processing instructions (if non-empty), + % (initial) args follow + \ifblank{#2}{\forest@process@a{#1}}{\forest@process@a{#1}{#2}}% +} +\Inline\def\forest@process@a#1#2{% + \begingroup + \forest@process@left@clear + \forest@process@right@clear + \forest@process@saved@clear + \let\forest@process@savedtype\forestmathtype@generic + \ExpandIfT{forestdebug}{% + \edef\forest@process@debug@args{\unexpanded{#2}}% + \typeout{[forest .process] Start "\unexpanded{#2}"}% + }% + \csname forest@process@returnarray@#1\endcsname + \def\forest@topextend@next{% + \forest@process@catregime + \endlinechar=-1 + \scantokens{#2}% + \forest@process@finish + }% + \forest@process@right@topextend +} +\pgfkeys{% + /handlers/.process/.code={% + \forest@process{true}#1\forest@eov + \edef\forest@marshal{% + \noexpand\pgfkeysalso{\noexpand\pgfkeyscurrentpath=\forest@process@result@values}% + }\forest@marshal + }, + /forest/copy command key={/handlers/.process}{/handlers/.process args}, +} +\def\forest@process@finish{% + \ifforest@process@returnarray@ + \forest@process@finish@array + \global\let\forest@process@result@type\forest@result@type@array \else - \apptotoks\forest@processargs@result{{#1}}% - \let\forest@processargs@next\forest@processargs@appremainingargs - \fi - \forest@processargs@next#2\forest@END -} -\def\forest@processargs@done#1\forest@END{% - \pgfkeysalso{\pgfkeyscurrentpath/.expanded=\the\forest@processargs@result}% -} -\csdef{forest@processargs@ins@_}#1\forest@END#2#3\forest@END{% no processing - % #1 = rest of ins, #2 = first arg, #3 = rest of args - \forest@processargs@maybeappend - \forest@processargs@current{#2}% - \forest@processargs@appendtrue - \forest@processargs@getins#1\forest@END#3\forest@END -} -\csdef{forest@processargs@ins@x}#1\forest@END#2#3\forest@END{% expand - % #1 = rest of ins, #2 = first arg, #3 = rest of args - \forest@processargs@maybeappend - \etotoks\forest@processargs@current{#2}% - \forest@processargs@appendtrue - \forest@processargs@getins#1\forest@END#3\forest@END -} -\csdef{forest@processargs@ins@o}#1\forest@END#2#3\forest@END{% expand once - % #1 = rest of ins, #2 = first arg, #3 = rest of args - \forest@processargs@maybeappend - \expandafter\forest@processargs@current\expandafter{#2}% - \forest@processargs@appendtrue - \forest@processargs@getins#1\forest@END#3\forest@END -} -\csdef{forest@processargs@ins@O}#1\forest@END#2#3\forest@END{% option - % #1 = rest of ins, #2 = first arg, #3 = rest of args - \forest@processargs@maybeappend - \etotoks\forest@processargs@current{\forestoption{#2}}% - \forest@processargs@appendtrue - \forest@processargs@getins#1\forest@END#3\forest@END -} -\csdef{forest@processargs@ins@R}#1\forest@END#2#3\forest@END{% register - % #1 = rest of ins, #2 = first arg, #3 = rest of args - \forest@processargs@maybeappend - \etotoks\forest@processargs@current{\forestregister{#2}}% - \forest@processargs@appendtrue - \forest@processargs@getins#1\forest@END#3\forest@END -} -\csdef{forest@processargs@ins@P}#1\forest@END#2#3\forest@END{% pgfmath expression - % #1 = rest of ins, #2 = first arg, #3 = rest of args - \forest@processargs@maybeappend - \pgfmathparse{#2}% - \expandafter\forest@processargs@current\expandafter{\pgfmathresult}% - \forest@processargs@appendtrue - \forest@processargs@getins#1\forest@END#3\forest@END -} -\csdef{forest@processargs@ins@+}#1\forest@END#2\forest@END{% join processors - \forest@processargs@appendfalse + \forest@process@finish@single + \fi + \ifforestdebugprocess\forest@process@debug@end\fi + \endgroup +} +\def\forest@process@finish@single{% + \edef\forest@temp{forest@process@finish@single@% + \the\numexpr\forest@process@left@N-\forest@process@left@M\relax + \the\numexpr\forest@process@right@N-\forest@process@right@M\relax + }% + \ifcsname\forest@temp\endcsname + \csname\forest@temp\endcsname + \global\let\forest@process@result\forest@temp + \else + \forest@process@lengtherror + \fi + \global\let\forest@process@result@type\forestmathresulttype +} +\csdef{forest@process@finish@single@10}{\forest@process@left@toppop\forest@temp} +\csdef{forest@process@finish@single@01}{\forest@process@right@toppop\forest@temp} +\def\forest@process@finish@array{% + \forest@process@result@clear + \forest@temp@count\forest@process@left@M\relax + \forest@loop + \ifnum\forest@temp@count<\forest@process@left@N\relax + \forest@process@left@get@{\the\forest@temp@count}\forest@temp + \forest@process@result@letappend\forest@temp + \advance\forest@temp@count1 + \forest@repeat + \forest@temp@count\forest@process@right@M\relax + \forest@loop + \ifnum\forest@temp@count<\forest@process@right@N\relax + \forest@process@right@get@{\the\forest@temp@count}\forest@temp + \forest@process@result@letappend\forest@temp + \advance\forest@temp@count1 + \forest@repeat +} +\ifforestdebug + \let\forest@process@d\forest@process@b + \def\forest@process@b#1\forest@eov{% save and print initial arguments + \edef\forest@process@debug@args{\unexpanded{#1}}% + \typeout{[forest .process] Start "\unexpanded{#1}"}% + \forest@process@d#1\forest@eov + } +\fi +\def\forest@process@debug@end{% + \typeout{[forest .process] \space\space\space End "\expandonce{\forest@process@debug@args}" -> "\forest@process@left@values\forest@process@right@values"}% +} +\def\forest@process@lengtherror{% + \PackageError{forest}{% + The ".process" expression was expected to evaluate to a single argument, + but the result is \the\forest@process@result@N + \space items long.}{}% +} +\def\forest@def@processor#1{% + {% + \def\forest@dp@double##1{% + \gdef\forest@global@temp{\forest@def@processor@{#1}{##1}}% + }% + \let\\\forest@dp@double + \catcode`#1=13 + \scantokens{\\#1}% + }% + \forest@global@temp +} +\def\forest@def@processor@#1#2{% + % #1 = instruction char (normal catcode), #2 = instruction char (active) + % #3 = default n (optional numeric arg, which precedes any other args; + % if the default is empty, this means no optional n) + % #4 = args spec, + % #5 = code + \eappto\forest@process@catregime{% + \unexpanded{\let#2}\expandonce{\csname forest@processor@#1\endcsname}% + \unexpanded{\catcode`#1=13 }% + }% + \def\forest@def@processor@inschar{#1}% + \forest@def@processor@@ +} +\def\forest@def@processor@@#1{% + \ifstrempty{#1}{% + \forest@def@processor@@non + }{% + \def\forest@def@processor@@default@n{#1}% + \forest@def@processor@@n + }% +} +\def\forest@def@processor@@non#1#2{% #1=args spec, #2=code + \csedef{forest@processor@\forest@def@processor@inschar}#1{% + \relax %% we need this (see above) + \unexpanded{#2}% + \expandafter\forest@def@processor@debuginfo\expandafter{% + \expandafter"\forest@def@processor@inschar"\ifstrempty{#1}{}{(#1)}}% + \ignorespaces + }% +} +\def\forest@def@processor@@n{% + \@ifnextchar*% + {\forest@temptrue\forest@def@processor@@n@}% + {\forest@tempfalse\forest@def@processor@@n@@}% +} +\def\forest@def@processor@@n@*{\forest@def@processor@@n@@} +\def\forest@def@processor@@n@@#1#2{% #1=args spec, #2=code + \csedef{forest@processor@\forest@def@processor@inschar}{% + \relax %% we need this (see above) + \noexpand\forestprocess@get@n + {\forest@def@processor@@default@n}% + \expandonce{\csname forest@processor@\forest@def@processor@inschar @\endcsname}% + }% + \ifforest@temp + \csedef{forest@processor@\forest@def@processor@inschar @}{% + \noexpand\forest@repeat@n@times{\forest@process@n}{% + \expandonce{\csname forest@processor@\forest@def@processor@inschar @rep\endcsname}% + }% + }% + \fi + \edef\forest@temp{% + \forest@def@processor@inschar + \ifforest@temp\else\noexpand\the\forest@process@n\fi + "}% + \csedef{forest@processor@\forest@def@processor@inschar @\ifforest@temp rep\fi}#1{% + \unexpanded{#2}% + \expandafter\forest@def@processor@debuginfo\expandafter{% + \forest@temp + \ifstrempty{#1}{}{(#1)}}% + }% +} +\def\forest@def@processor@debuginfo#1{% #1 = instruction call + \ifforestdebug + \expandonce{\forest@processor@debuginfo@template{#1}}% + \fi +} +\def\forest@processor@debuginfo@template#1{% + \ifforestdebugprocess + \edef\forest@temp@left{\forest@process@left@values}% + \edef\forest@temp@right{\forest@process@right@values}% + \edef\forest@temp@saved{\forest@process@saved@values}% + \typeout{[forest .process]\space\space\space\space After #1: left="\expandonce{\forest@temp@left}", right="\expandonce{\forest@temp@right}", saved="\expandonce{\forest@temp@saved}", type=\forestmathresulttype}% + \fi +} +\newcount\forest@process@n +\def\forestprocess@get@n#1#2{% + \def\forestprocess@default@n{#1}% + \let\forestprocess@after@get@n@#2% + \afterassignment\forestprocess@get@n@\forest@process@n=0% +} +\def\forestprocess@get@n@{% + \ifnum\forest@process@n=0 + \forest@process@n\forestprocess@default@n\relax + \fi + \forestprocess@after@get@n@ +} +\forest@def@processor{_}{1}*{}{% no processing, no type + \forest@process@right@bottompop\forest@temp + \forest@process@left@letappend\forest@temp +} +\forest@def@processor{n}{1}*{}{% numexpr + \forest@process@right@bottompop\forest@temp + \forest@process@left@esetappend{\number\numexpr\forest@temp}% + \let\forestmathresulttype\forestmathtype@count +} +\forest@def@processor{d}{1}*{}{% dimexpr + \forest@process@right@bottompop\forest@temp + \forest@process@left@esetappend{\the\dimexpr\forest@temp}% + \let\forestmathresulttype\forestmathtype@dimen +} +\forest@def@processor{P}{1}*{}{% pgfmath expression + \forest@process@right@bottompop\forest@temp + \pgfmathparse{\forest@temp}% + \forest@process@left@letappend\pgfmathresult + \let\forestmathresulttype\forestmathtype@unitless +} +\forest@def@processor{t}{1}*{}{% text + \forest@process@right@bottompop\forest@temp + \forest@process@left@letappend\forest@temp + \let\forestmathresulttype\forestmathtype@textasc +} +\forest@def@processor{-}{}{}{% toggle ascending/descending + \forest@process@left@toppop\forestmathresult + \csname forest@processor@-@\forestmathresulttype\endcsname + \forest@process@left@letappend\forestmathresult +} +\cslet{forest@processor@-@\forestmathtype@generic}\relax +\csdef{forest@processor@-@\forestmathtype@count}{% + \forestmathadd{\forestmathzero}{-\forestmathresult}} +\csletcs{forest@processor@-@\forestmathtype@dimen} + {forest@processor@-@\forestmathtype@count} +\csletcs{forest@processor@-@\forestmathtype@unitless} + {forest@processor@-@\forestmathtype@count} +\csdef{forest@processor@-@\forestmathtype@textasc}{% + \let\forestmathresulttype\forestmathtype@textdesc} +\csdef{forest@processor@-@\forestmathtype@textdesc}{% + \let\forestmathresulttype\forestmathtype@textasc} + +\forest@def@processor{c}{}{}{% to lowercase + \forest@process@right@bottompop\forest@temp + \expandafter\lowercase\expandafter{\expandafter\def\expandafter\forest@temp\expandafter{\forest@temp}}% + \forest@process@left@letappend\forest@temp +} +\forest@def@processor{C}{}{}{% to uppercase + \forest@process@right@bottompop\forest@temp + \expandafter\uppercase\expandafter{\expandafter\def\expandafter\forest@temp\expandafter{\forest@temp}}% + \forest@process@left@letappend\forest@temp +} +\forest@def@processor{x}{}{}{% expand + \forest@process@right@bottompop\forest@temp + \forest@process@left@esetappend{\forest@temp}% + \let\forestmathresulttype\forestmathtype@generic +} +\forest@def@processor{o}{1}{}{% expand once (actually, \forest@count@n times) + \forest@process@right@bottompop\forest@temp + \forest@repeat@n@times{\forest@process@n}{% + \expandafter\expandafter\expandafter\def + \expandafter\expandafter\expandafter\forest@temp + \expandafter\expandafter\expandafter{\forest@temp}% + }% + \expandafter\forest@process@left@setappend\expandafter{\forest@temp}% + \let\forestmathresulttype\forestmathtype@generic +} +\forest@def@processor{O}{1}*{}{% option + \forest@process@right@bottompop\forest@temp + \expandafter\forestRNO@getvalueandtype\expandafter{\forest@temp}\forest@tempvalue\forest@temp@type + \let\forestmathresulttype\forest@temp@type + \forest@process@left@letappend\forest@tempvalue +} +\forest@def@processor{R}{1}*{}{% register + \forest@process@right@bottompop\forest@temp + \forestrget{\forest@temp}\forest@tempvalue + \forest@process@left@letappend\forest@tempvalue + \pgfkeysgetvalue{/forest/\forest@temp/@type}\forest@temp@type + \let\forestmathresulttype\forest@temp@type +} +\forest@def@processor{+}{1}*{}{% join processors = pop one from result + \forest@process@left@toppop\forest@temp + \forest@process@right@letprepend\forest@temp +} +\forest@def@processor{u}{}{}{% ungroup: remove braces and leave in the argument list + \forest@process@right@bottompop\forest@temp + \forest@temparray@clear + \let\forestmathresulttype\forestmathtype@generic + \let\forest@topextend@next\forest@processor@u@ + \expandafter\forest@temparray@topextend\forest@temp\forest@eov +} +\def\forest@processor@u@{% + \forest@loop + \ifnum\forest@temparray@N>0 + \forest@temparray@toppop\forest@temp + \expandafter\forest@process@right@setprepend\expandafter{\expandafter{\forest@temp}}% + \forest@repeat +} +\def\forest@process@check@mn#1#2#3#4{% + % #1 = processor, #2 = given n, #3/#4 = lower/upper bound (inclusive) + \ifnum#3>#2\relax + \forest@process@check@n@error{#1}{#2}{#3<=}{<=#4}% + \else + \ifnum#4<#2\relax + \forest@process@check@n@error{#1}{#2}{#3<=}{<=#4}% + \fi + \fi +} +\def\forest@process@check@m#1#2#3{% + % #1 = processor, #2 = given n, #3 = lower bound (inclusive) + \ifnum#2<#3\relax + \forest@process@check@n@error{#1}{#2}{#3<=}{}% + \fi +} +\def\forest@process@check@n@error#1#2#3#4{% + \PackageError{forest}{'.process' instruction '#1' requires a numeric modifier #3n#4, but n="#2" was given.}{}% +} +\newif\ifforest@process@W +\forest@def@processor{w}{1}{}{% consuming wrap: first test 1<=#1<=9 + \forest@process@Wtrue + \forest@process@check@mn{w}{0\the\forest@process@n}{1}{9}% + \expandafter\forest@processor@wW@\expandafter{\the\forest@process@n}% +} +\forest@def@processor{W}{1}{}{% nonconsuming wrap: first test 1<=#1<=9 + \forest@process@Wfalse + \forest@process@check@mn{W}{0\the\forest@process@n}{1}{9}% + \expandafter\forest@processor@wW@\expandafter{\the\forest@process@n}% +} +\def\forest@processor@wW@#1{% + \forest@process@left@checkindex{\forest@process@left@N-#1}% \edef\forest@marshal{% - \unexpanded{\forest@processargs@getins#1\forest@END}{\the\forest@processargs@current}\unexpanded{#2\forest@END}% + \edef\noexpand\forest@temp@args{% + \noexpand\forest@process@left@valuesfromrange + {\number\numexpr\forest@process@left@N-#1}% + {\the\forest@process@left@N}% + }% }\forest@marshal + \ifforest@process@W + \advance\forest@process@left@N-#1\relax + \fi + \forest@process@right@bottompop\forest@temp@macrobody + \expandafter\forest@def@n\expandafter\forest@process@temp@macro\expandafter{\expandafter#1\expandafter}\expandafter{\forest@temp@macrobody}% + \expandafter\expandafter\expandafter\forest@process@left@setappend\expandafter\expandafter\expandafter{\expandafter\forest@process@temp@macro\forest@temp@args}% + \let\forestmathresulttype\forestmathtype@generic +} +\def\forest@def@n#1#2{\csname forest@def@n@#2\endcsname#1} +\csdef{forest@def@n@1}#1{\def#1##1} +\csdef{forest@def@n@2}#1{\def#1##1##2} +\csdef{forest@def@n@3}#1{\def#1##1##2##3} +\csdef{forest@def@n@4}#1{\def#1##1##2##3##4} +\csdef{forest@def@n@5}#1{\def#1##1##2##3##4##5} +\csdef{forest@def@n@6}#1{\def#1##1##2##3##4##5##6} +\csdef{forest@def@n@7}#1{\def#1##1##2##3##4##5##6##7} +\csdef{forest@def@n@8}#1{\def#1##1##2##3##4##5##6##7##8} +\csdef{forest@def@n@9}#1{\def#1##1##2##3##4##5##6##7##8##9} +\forest@def@processor{s}{1}{}{% + \forest@temptrue % delete the originals + \expandafter\forest@processor@save\expandafter{% + \the\numexpr\forest@process@left@N-\forest@process@n}} +\forest@def@processor{S}{1}{}{% + \forest@tempfalse % keep the originals + \expandafter\forest@processor@save\expandafter{% + \the\numexpr\forest@process@left@N-\forest@process@n}} +\def\forest@processor@save#1{% + \forest@process@left@checkindex{#1}% + \forest@temp@count#1 + \forest@loop + \ifnum\forest@temp@count<\forest@process@left@N\relax + \forest@process@left@get@{\the\forest@temp@count}\forest@temp + \forest@process@saved@letappend\forest@temp + \advance\forest@temp@count+1 + \forest@repeat + \let\forest@process@savedtype\forestmathresulttype + \ifforest@temp + \forest@process@left@N=#1 + \fi +} +\forest@def@processor{l}{0}{}{% + \forest@temptrue + \forest@processor@U@@ +} +\forest@def@processor{L}{0}{}{% + \forest@tempfalse + \forest@processor@U@@ +} + +\def\forest@processor@U@@{% + \ifnum\forest@process@n=0 + \forest@process@n\forest@process@saved@N\relax + \fi + \expandafter\forest@processor@U@@@\expandafter{% + \the\numexpr\forest@process@saved@N-\forest@temp@count}% } -\csdef{forest@processargs@ins@r}#1\forest@END#2#3\forest@END{% reverse keylist - % #1 = rest of ins, #2 = first arg, #3 = rest of args - \forest@processargs@maybeappend - \forest@processargs@current{}% - \pgfqkeys{/forest}{split={#2}{,}{reverse@keylist}}% - \forest@processargs@appendtrue - \forest@processargs@getins#1\forest@END#3\forest@END +\def\forest@processor@U@@@#1{% + \forest@temp@count#1 + \forest@loop + \ifnum\forest@temp@count<\forest@process@saved@N\relax + \forest@process@saved@get@{\the\forest@temp@count}\forest@temp + \forest@process@left@letappend\forest@temp + \advance\forest@temp@count1 + \forest@repeat + \let\forestmathresulttype\forest@process@savedtype + \ifforest@temp + \let\forest@process@savedtype\forest@result@type@any + \forest@process@saved@N#1 + \fi +} +\forest@def@processor{&}{2}{}{% and + \def\forest@tempa{1}% + \forest@repeat@n@times{\forest@process@n}{% + \forest@process@left@bottompop\forest@tempb + \edef\forest@tempa{\ifnum10<\forest@tempa\forest@tempb\space 1\else0\fi}% + }% + \forest@process@left@esetappend{\forest@tempa}% + \let\forestmathresulttype\forestmathtype@count +} +\forest@def@processor{|}{2}{}{% or + \def\forest@tempa{0}% + \forest@repeat@n@times{\forest@process@n}{% + \forest@process@left@bottompop\forest@tempb + \edef\forest@tempa{\ifnum0=\forest@tempa\forest@tempb\space 0\else1\fi}% + }% + \forest@process@left@esetappend{\forest@tempa}% + \let\forestmathresulttype\forestmathtype@count +} +\forest@def@processor{!}{}{}{% not + \forest@process@left@toppop\forest@temp + \forest@process@left@esetappend{\ifnum0=\forest@temp\space 1\else0\fi}% + \let\forestmathresulttype\forestmathtype@count +} +\forest@def@processor{?}{}{}{% + \forest@process@left@toppop\forest@temp + \forest@process@right@bottompop\forest@tempa + \forest@process@right@bottompop\forest@tempb + \ifnum\forest@temp=0 + \forest@process@right@letprepend\forest@tempb + \else + \forest@process@right@letprepend\forest@tempa + \fi + \let\forestmathresulttype\forestmathtype@generic +} +\forest@def@processor{=}{}{}{% + \forest@process@left@toppop\forest@tempa + \forest@process@left@toppop\forest@tempb + \forest@process@left@esetappend{\ifx\forest@tempa\forest@tempb 1\else0\fi}% + \let\forestmathresulttype\forestmathtype@count +} +\forest@def@processor{<}{}{}{% + \forest@process@left@toppop\forest@tempb + \forest@process@left@toppop\forest@tempa + \ifx\forestmathresulttype\forestmathtype@generic + \forest@cmp@error\forest@tempa\forest@tempb + \else + \forestmathlt{\forest@tempa}{\forest@tempb}% + \forest@process@left@esetappend{\forestmathresult}% + \fi +} +\forest@def@processor{>}{}{}{% + \forest@process@left@toppop\forest@tempb + \forest@process@left@toppop\forest@tempa + \ifx\forestmathresulttype\forestmathtype@generic + \forest@cmp@error\forest@tempa\forest@tempb + \else + \forestmathgt{\forest@tempa}{\forest@tempb}% + \forest@process@left@esetappend{\forestmathresult}% + \fi +} +\forest@def@processor{r}{}{}{% reverse keylist + \forest@process@right@bottompop\forest@temp + \expandafter\forest@processor@r@\expandafter{\forest@temp}% +} +\def\forest@processor@r@#1{% + \forest@temp@toks{}% + \def\forest@tempcomma{}% + \pgfqkeys{/forest}{split={#1}{,}{process@rk}}% + \forest@process@left@esetappend{\the\forest@temp@toks}% + \let\forestmathresulttype\forestmathtype@generic } \forestset{% - reverse@keylist/.code={% - \epretotoks\forest@processargs@current{#1,}% - }, + process@rk/.code={% + \epretotoks\forest@temp@toks{#1\forest@tempcomma}% + \def\forest@tempcomma{,}% + }% } \def\forest@pgfmathhelper@register@toks#1#2{% #1 is discarded: it is present only for analogy with options \forestrget{#2}\pgfmathresult } \def\forest@pgfmathhelper@register@dimen#1#2{% \forestrget{#2}\forest@temp - \pgfmathparse{+\forest@temp}% + \edef\pgfmathresult{\expandafter\Pgf@geT\forest@temp}% } \def\forest@pgfmathhelper@register@count#1#2{% - \forestrget{#2}\forest@temp - \pgfmathtruncatemacro\pgfmathresult{\forest@temp}% + \forestrget{#2}\pgfmathresult } \def\forest@declareregisterhandler#1#2{%#1=handler for specific type,#2=option name - \pgfkeyssetvalue{/forest/#2/node@or@reg}{register}% + \pgfkeyssetvalue{/forest/#2/node@or@reg}{}% empty = register (node id=node) \forest@convert@others@to@underscores{#2}\forest@pgfmathoptionname \edef\forest@marshal{% \noexpand#1{/forest/#2}{/forest}{#2}{\forest@pgfmathoptionname}% @@ -2166,6 +3386,7 @@ \pgfkeyssetvalue{#1/option@name}{#3}% \pgfkeyssetvalue{#1+/option@name}{#3}% \pgfkeyssetvalue{#2/+#3/option@name}{#3}% + \pgfkeyslet{#1/@type}\forestmathtype@generic % for .process & co \pgfmathdeclarefunction{#4}{1}{\forest@pgfmathhelper@register@toks{##1}{#3}}% } \def\forest@declareautowrappedtoksregister@handler#1#2#3#4{% #1=key,#2=path,#3=name,#4=pgfmathname,#5=infix @@ -2190,24 +3411,41 @@ \pgfkeysalso{##3}% \fi }, + #2/if #3</.code n args={3}{% + \forestrget{#3}\forest@temp@option@value + \ifdim\forest@temp@option@value>##1\relax + \pgfkeysalso{##3}% + \else + \pgfkeysalso{##2}% + \fi + }, + #2/if #3>/.code n args={3}{% + \forestrget{#3}\forest@temp@option@value + \ifdim\forest@temp@option@value<##1\relax + \pgfkeysalso{##3}% + \else + \pgfkeysalso{##2}% + \fi + }, }% + \pgfkeyslet{#1/@type}\forestmathtype@dimen % for .process & co \pgfmathdeclarefunction{#4}{1}{\forest@pgfmathhelper@register@dimen{##1}{#3}}% } \def\forest@declaredimenregister@handler#1#2#3#4{% #1=key,#2=path,#3=name,#4=pgfmathname \forest@declarereadonlydimenregister@handler{#1}{#2}{#3}{#4}% \pgfkeysalso{% #1/.code={% - \pgfmathsetlengthmacro\forest@temp{##1}% + \forestmathsetlengthmacro\forest@temp{##1}% \forestrlet{#3}\forest@temp }, #1+/.code={% - \pgfmathsetlengthmacro\forest@temp{##1}% + \forestmathsetlengthmacro\forest@temp{##1}% \pgfutil@tempdima=\forestrve{#3} \advance\pgfutil@tempdima\forest@temp\relax \forestreset{#3}{\the\pgfutil@tempdima}% }, #1-/.code={% - \pgfmathsetlengthmacro\forest@temp{##1}% + \forestmathsetlengthmacro\forest@temp{##1}% \pgfutil@tempdima=\forestrve{#3} \advance\pgfutil@tempdima-\forest@temp\relax \forestreset{#3}{\the\pgfutil@tempdima}% @@ -2264,36 +3502,53 @@ \pgfkeysalso{##3}% \fi }, + #2/if #3</.code n args={3}{% + \forestrget{#3}\forest@temp@option@value + \ifnum\forest@temp@option@value>##1\relax + \pgfkeysalso{##3}% + \else + \pgfkeysalso{##2}% + \fi + }, + #2/if #3>/.code n args={3}{% + \forestrget{#3}\forest@temp@option@value + \ifnum\forest@temp@option@value<##1\relax + \pgfkeysalso{##3}% + \else + \pgfkeysalso{##2}% + \fi + }, }% + \pgfkeyslet{#1/@type}\forestmathtype@count % for .process & co \pgfmathdeclarefunction{#4}{1}{\forest@pgfmathhelper@register@count{##1}{#3}}% } \def\forest@declarecountregister@handler#1#2#3#4{% #1=key,#2=path,#3=name,#4=pgfmathname \forest@declarereadonlycountregister@handler{#1}{#2}{#3}{#4}% \pgfkeysalso{ #1/.code={% - \pgfmathtruncatemacro\forest@temp{##1}% + \forestmathtruncatemacro\forest@temp{##1}% \forestrlet{#3}\forest@temp }, #1+/.code={% - \pgfmathtruncatemacro\forest@temp{##1}% + \forestmathtruncatemacro\forest@temp{##1}% \c@pgf@counta=\forestrve{#3}\relax \advance\c@pgf@counta\forest@temp\relax \forestreset{#3}{\the\c@pgf@counta}% }, #1-/.code={% - \pgfmathtruncatemacro\forest@temp{##1}% + \forestmathtruncatemacro\forest@temp{##1}% \c@pgf@counta=\forestrve{#3}\relax \advance\c@pgf@counta-\forest@temp\relax \forestreset{#3}{\the\c@pgf@counta}% }, #1*/.code={% - \pgfmathtruncatemacro\forest@temp{##1}% + \forestmathtruncatemacro\forest@temp{##1}% \c@pgf@counta=\forestrve{#3}\relax \multiply\c@pgf@counta\forest@temp\relax \forestreset{#3}{\the\c@pgf@counta}% }, #1:/.code={% - \pgfmathtruncatemacro\forest@temp{##1}% + \forestmathtruncatemacro\forest@temp{##1}% \c@pgf@counta=\forestrve{#3}\relax \divide\c@pgf@counta\forest@temp\relax \forestreset{#3}{\the\c@pgf@counta}% @@ -2337,16 +3592,13 @@ \def\forest@declarebooleanregister@handler#1#2#3#4{% #1=key,#2=path,#3=name,#4=pgfmathname \pgfkeysalso{% #1/.code={% - \ifstrequal{##1}{1}{% - \forestrset{#3}{1}% + \ifcsdef{forest@bh@\detokenize{##1}}{% + \letcs\forest@temp{forest@bh@\detokenize{##1}}% }{% - \ifstrequal{##1}{0}{% - \forestrset{#3}{0}% - }{% - \pgfmathifthenelse{##1}{1}{0}% - \forestrlet{#3}\pgfmathresult - }% + \forestmathtruncatemacro\forest@temp{##1}% + \ifx\forest@temp0\else\def\forest@temp{1}\fi }% + \forestrlet{#3}\forest@temp }, #1/.default=1, #2/not #3/.code={\forestrset{#3}{0}}, @@ -2360,6 +3612,7 @@ }, }% \pgfkeyssetvalue{#1/option@name}{#3}% + \pgfkeyslet{#1/@type}\forestmathtype@count % for .process & co \pgfmathdeclarefunction{#4}{1}{\forest@pgfmathhelper@register@count{##1}{#3}}% } \forestset{ @@ -2526,12 +3779,17 @@ preamble'={}, declare autowrapped toks={content}{}, % #1 = which option to split, #2 = separator (one char!), #3 = receiving options - %%% begin listing region: split_option - split option/.style n args=3{split/.process args={O}{#1}{#2}{#3}} - %%% end listing region: split_option - , - split register/.style n args=3{% #1 = which register to split, #2 = separator (one char!), #3 = receiving options - split/.process args={R}{#1}{#2}{#3}, + split option/.code n args=3{% + \forestRNOget{#1}\forest@temp + \edef\forest@marshal{% + \noexpand\pgfkeysalso{split={\expandonce{\forest@temp}}\unexpanded{{#2}{#3}}}% + }\forest@marshal + }, + split register/.code n args=3{% #1 = which register to split, #2 = separator (one char!), #3 = receiving options + \forestrget{#1}\forest@temp + \edef\forest@marshal{% + \noexpand\pgfkeysalso{split={\expandonce{\forest@temp}}\unexpanded{{#2}{#3}}}% + }\forest@marshal }, TeX={% \def\forest@split@sourcevalues{}% @@ -2729,7 +3987,7 @@ get node boundary/.code={% \forestoget{@boundary}\forest@node@boundary \def#1{}% - \forest@extendpath#1\forest@node@boundary{\pgfpoint{\forestove{x}}{\forestove{y}}}% + \forest@extendpath#1\forest@node@boundary{\pgfqpoint{\forestove{x}}{\forestove{y}}}% }, % get min l tree boundary/.code={% % \forest@get@tree@boundary{negative}{\the\numexpr\forestove{grow}-90\relax}#1}, @@ -2785,7 +4043,7 @@ \def\forest@get@tree@boundary#1#2#3{%#1=pos/neg,#2=grow,#3=receiving cs \def#3{}% \forest@node@getedge{#1}{#2}\forest@temp@boundary - \forest@extendpath#3\forest@temp@boundary{\pgfpoint{\forestove{x}}{\forestove{y}}}% + \forest@extendpath#3\forest@temp@boundary{\pgfqpoint{\forestove{x}}{\forestove{y}}}% } \def\forest@setter@node{\forest@cn}% \def\forest@relatednode@option@compat@ignoreinvalidsteps#1{#1} @@ -2808,33 +4066,31 @@ \forestset{ for tree'/.style 2 args={#1,for children={for tree'={#1}{#2}},#2}, if/.code n args={3}{% - \pgfmathparse{#1}% - \ifnum\pgfmathresult=0 + \forestmathtruncatemacro\forest@temp{#1}% + \ifnum\forest@temp=0 \@escapeif{\pgfkeysalso{#3}}% \else \@escapeif{\pgfkeysalso{#2}}% \fi }, + %LaTeX if/.code n args={3}{#1{\pgfkeysalso{#2}}{\pgfkeysalso{#3}}}, if nodewalk valid/.code n args={3}{% - \edef\forest@marshal{% - \unexpanded{\forest@forthis{% - \forest@nodewalk{% - on invalid={fake}{#1}, - TeX={\global\let\forest@global@temp\forest@cn} - }{}% - }% - \def\forest@cn}{\forest@cn}\unexpanded{% - \ifnum\forest@global@temp=0 - \@escapeif{\pgfkeysalso{#3}}% - \else - \@escapeif{\pgfkeysalso{#2}}% - \fi}% - }\forest@marshal + \forest@forthis{% + \forest@configured@nodewalk{independent}{inherited}{fake}{% + #1, + TeX={\global\let\forest@global@temp\forest@cn} + }{}% + }% + \ifnum\forest@global@temp=0 + \@escapeif{\pgfkeysalso{#3}}% + \else + \@escapeif{\pgfkeysalso{#2}}% + \fi }, if nodewalk empty/.code n args={3}{% \forest@forthis{% - \forest@nodewalk{% - on invalid={fake}{#1}, + \forest@configured@nodewalk{independent}{independent}{fake}{% + #1, TeX={\global\let\forest@global@temp\forest@nodewalk@n}, }{}% }% @@ -2844,39 +4100,46 @@ \@escapeif{\pgfkeysalso{#3}}% \fi }, + if current nodewalk empty/.code 2 args={% + \ifnum\forest@nodewalk@n=0 + \@escapeif{\pgfkeysalso{#1}}% + \else + \@escapeif{\pgfkeysalso{#2}}% + \fi + }, where/.style n args={3}{for tree={if={#1}{#2}{#3}}}, where nodewalk valid/.style n args={3}{for tree={if nodewalk valid={#1}{#2}{#3}}}, where nodewalk empty/.style n args={3}{for tree={if nodewalk empty={#1}{#2}{#3}}}, repeat/.code 2 args={% - \pgfmathtruncatemacro\forest@temp{#1}% + \forestmathtruncatemacro\forest@temp{#1}% \expandafter\forest@repeatkey\expandafter{\forest@temp}{#2}% }, until/.code 2 args={% \ifstrempty{#1}{% \forest@untilkey{\ifnum\forest@cn=0\else\relax\forestloopbreak\fi}{on invalid={fake}{#2}}% }{% - \forest@untilkey{\pgfmathifthenelse{#1}{"\noexpand\forestloopbreak"}{""}\pgfmathresult}{#2}% + \forest@untilkey{\forestmath@if{#1}{\forestloopbreak}{}}{#2}% }% }, while/.code 2 args={% \ifstrempty{#1}{% \forest@untilkey{\ifnum\forest@cn=0\relax\forestloopbreak\fi}{on invalid={fake}{#2}}% }{% - \forest@untilkey{\pgfmathifthenelse{not(#1)}{"\noexpand\forestloopbreak"}{""}\pgfmathresult}{#2}% + \forest@untilkey{\forestmath@if{#1}{}{\forestloopbreak}}{#2}% }% }, do until/.code 2 args={% \ifstrempty{#1}{% \forest@dountilkey{\ifnum\forest@cn=0\else\relax\forestloopbreak\fi}{on invalid={fake}{#2}}% }{% - \forest@dountilkey{\pgfmathifthenelse{#1}{"\noexpand\forestloopbreak"}{""}\pgfmathresult}{#2}% + \forest@dountilkey{\forestmath@if{#1}{\forestloopbreak}{}}{#2}% }% }, do while/.code 2 args={% \ifstrempty{#1}{% \forest@dountilkey{\ifnum\forest@cn=0\relax\forestloopbreak\fi}{on invalid={fake}{#2}}% }{% - \forest@dountilkey{\pgfmathifthenelse{not(#1)}{"\noexpand\forestloopbreak"}{""}\pgfmathresult}{#2}% + \forest@dountilkey{\forestmath@if{#1}{}{\forestloopbreak}}{#2}% }% }, until nodewalk valid/.code 2 args={% @@ -2981,48 +4244,168 @@ \forest@aggregate@pgfmathpostparse@macro } \let\forest@aggregate@pgfmathpostparse\relax -\pgfkeys{ +\forestset{ /handlers/.aggregate/.code n args=4{% - % #1 = start value - % #2 = pgfmath expression for every step - % #3 = pgfmath expression for after walk + % #1 = start value (forestmath) + % #2 = forestmath expression that calculates "aggregate result" at each step + % #3 = forestmath expression that calculates "aggregate result" at the end of the nodewalk % #4 = nodewalk - \edef\forest@marshal{% - \unexpanded{\forest@aggregate{#1}{#2}{#3}{#4}}{\pgfkeyscurrentpath}% - }\forest@marshal + \forest@aggregate@handler{\forest@aggregate@generic{#1}{#2}{#3}{#4}}% + }, + /handlers/.sum/.code 2 args={% #1=forestmath, #2=nodewalk + \forest@aggregate@handler{\forest@aggregate@sum{#1}{#2}}% + }, + /handlers/.count/.code={% #1=nodewalk + \forest@aggregate@handler{\forest@aggregate@count{#1}}% + }, + /handlers/.average/.code 2 args={% #1=forestmath, #2=nodewalk + \forest@aggregate@handler{\forest@aggregate@average{#1}{#2}}% }, - /handlers/.sum/.style 2 args={/handlers/.aggregate={0}{(##1)+(#1)}{##1}{#2}}, - /handlers/.count/.style={/handlers/.aggregate={0}{1+(##1)}{##1}{#1}}, - /handlers/.average/.style 2 args={/handlers/.aggregate={0}{(##1)+(#1)}{##1/\forestregister{aggregate n}}{#2}}, - /handlers/.product/.style 2 args={/handlers/.aggregate={1}{(#1)*(##1)}{##1}{#2}}, - /handlers/.min/.style 2 args={/handlers/.aggregate={}{min(#1,##1)}{##1}{#2}}, - /handlers/.max/.style 2 args={/handlers/.aggregate={}{max(#1,##1)}{##1}{#2}}, - /forest/declare count register={aggregate n}, + /handlers/.product/.code 2 args={% #1=forestmath, #2=nodewalk + \forest@aggregate@handler{\forest@aggregate@product{#1}{#2}}% + }, + /handlers/.min/.code 2 args={% #1=forestmath, #2=nodewalk + \forest@aggregate@handler{\forest@aggregate@min{#1}{#2}}% + }, + /handlers/.max/.code 2 args={% #1=forestmath, #2=nodewalk + \forest@aggregate@handler{\forest@aggregate@max{#1}{#2}}% + }, + declare count register={aggregate n}, + declare toks register={aggregate value}, + declare toks register={aggregate result}, + aggregate result={}, } - -\def\forest@aggregate#1#2#3#4#5{% - % #5 = current path - \def\forest@aggregate@result{#1}% - \forest@forthis{% - \forestrset{aggregate n}{0}% - \forest@nodewalk{#4}{% - TeX={% - \forestreset{aggregate n}{\number\numexpr\forestrv{aggregate n}+1}% - \def\forest@marshal##1{\pgfmathparse{#2}}% - \expandafter\forest@marshal\expandafter{\forest@aggregate@result}% - \let\forest@aggregate@result\pgfmathresult - }% - }{}% +\def\forest@aggregate@handler#1{% + \edef\forest@marshal{% + \unexpanded{% + #1% + }{% + \noexpand\pgfkeysalso{\pgfkeyscurrentpath/.register=aggregate result}% }% - \def\forest@marshal##1{\pgfmathparse{#3}}% - \expandafter\forest@marshal\expandafter{\forest@aggregate@result}% - \let\forest@aggregate@result\pgfmathresult - \let\forest@temp@pgfmathpostparse\pgfmathpostparse - \let\pgfmathpostparse\forest@aggregate@pgfmathpostparse - \pgfmathqparse{\forest@aggregate@result pt}% - \let\pgfmathpostparse\forest@temp@pgfmathpostparse - \let\forest@aggregate@result\pgfmathresult - \pgfkeysalso{#5/.expand once=\forest@aggregate@result}% + }\forest@marshal +} +\def\forest@aggregate@pgfmathfunction@finish{% + \forestrget{aggregate result}\pgfmathresult +} +\pgfmathdeclarefunction{aggregate}{4}{% + \forest@aggregate@generic{#1}{#2}{#3}{#4}% + \forest@aggregate@pgfmathfunction@finish +} +\pgfmathdeclarefunction{aggregate_count}{1}{% + \forest@aggregate@sum{#1}% + \forest@aggregate@pgfmathfunction@finish +} +\pgfmathdeclarefunction{aggregate_sum}{2}{% + \forest@aggregate@sum{#1}{#2}% + \forest@aggregate@pgfmathfunction@finish +} +\pgfmathdeclarefunction{aggregate_product}{2}{% + \forest@aggregate@product{#1}{#2}% + \forest@aggregate@pgfmathfunction@finish +} +\pgfmathdeclarefunction{aggregate_average}{2}{% + \forest@aggregate@average{#1}{#2}% + \forest@aggregate@pgfmathfunction@finish +} +\pgfmathdeclarefunction{aggregate_min}{2}{% + \forest@aggregate@min{#1}{#2}% + \forest@aggregate@pgfmathfunction@finish +} +\pgfmathdeclarefunction{aggregate_max}{2}{% + \forest@aggregate@max{#1}{#2}% + \forest@aggregate@pgfmathfunction@finish +} +\def\forest@aggregate#1#2#3#4#5#6{% #1...#5=real args, + % #6=what to do with |aggregate result| register + % #1 = start value (forestmath) + % #2 = forestmath expression that calculates "aggregate current" at each step + % #3 = forestmath expression that calculates "aggregate result" at each step + % #4 = forestmath expression that calculates "aggregate result" at the end of the nodewalk + % #5 = nodewalk + \forest@saveandrestoreregister{aggregate result}{% + \forest@saveandrestoreregister{aggregate n}{% + \forest@aggregate@{#1}{#2}{#3}{#4}{#5}% + #6% + }% + }% +} +\def\forest@aggregate@generic#1#2#3#4{\forest@aggregate + {\forestmathparse{#1}}% + {}% + {\forestmathparse{#2}}% + {\forestmathparse{#3}}% + {#4}% +} +\def\forest@aggregate@sum#1#2{\forest@aggregate + {\forestmath@convert@fromto\forestmathtype@count\forestmathtype@generic{0}}% + {\forestmathparse{#1}}% + {\forestmathadd{\forestregister{aggregate value}}{\forestregister{aggregate result}}}% + {\forestrget{aggregate result}\forestmathresult}% + {#2}% +} +\def\forest@aggregate@count#1{\forest@aggregate + {\def\forestmathresult{1}}% + {\def\forestmathresult{1}}% + {\edef\forestmathresult{\the\numexpr\forestregister{aggregate result}+1}}% + {\forestrget{aggregate result}\forestmathresult}% + {#1}% +} +\def\forest@aggregate@average#1#2{\forest@aggregate + {\forestmath@convert@fromto\forestmathtype@count\forestmathtype@generic{0}}% + {\forestmathparse{#1}}% + {\forestmathadd{\forestregister{aggregate value}}{\forestregister{aggregate result}}}% + {\forestmathdivide@P{\forestregister{aggregate result}}{\forestregister{aggregate n}}}% + {#2}% +} +\def\forest@aggregate@product#1#2{\forest@aggregate + {\forestmath@convert@fromto\forestmathtype@count\forestmathtype@generic{1}}% + {\forestmathparse{#1}}% + {\forestmathmultiply{\forestregister{aggregate value}}{\forestregister{aggregate result}}}% + {\forestrget{aggregate result}\forestmathresult}% + {#2}% +} +\def\forest@aggregate@min#1#2{\forest@aggregate + {\def\forestmathresult{}}% + {\forestmathparse{#1}}% + {\forestmathmin{\forestregister{aggregate value}}{\forestregister{aggregate result}}}% + {\forestrget{aggregate result}\forestmathresult}% + {#2}% +} +\def\forest@aggregate@max#1#2{\forest@aggregate + {\def\forestmathresult{}}% + {\forestmathparse{#1}}% + {\forestmathmax{\forestregister{aggregate value}}{\forestregister{aggregate result}}}% + {\forestrget{aggregate result}\forestmathresult}% + {#2}% +} +\def\forest@aggregate@#1#2#3#4#5{% + % #1 = start value (forestmath) + % #2 = forestmath expression that calculates "aggregate current" at each step + % #3 = forestmath expression that calculates "aggregate result" at each step + % #4 = forestmath expression that calculates "aggregate result" at the end of the nodewalk + % #5 = nodewalk + #1% + \forestrlet{aggregate result}\forestmathresult + \forestrset{aggregate value}{}% + \forestrset{aggregate n}{0}% + \forest@forthis{% + \forest@nodewalk{#5}{% + TeX={% + \forestreset{aggregate n}{\number\numexpr\forestrv{aggregate n}+1}% + #2% + \forestrlet{aggregate value}\forestmathresult + #3% + \forestrlet{aggregate result}\forestmathresult + }% + }{}% + }% + #4% + \let\forest@temp@pgfmathpostparse\pgfmathpostparse + \let\pgfmathpostparse\forest@aggregate@pgfmathpostparse + \forestmath@convert@to\forestmathtype@dimen{\forestmathresult} + \pgfmathqparse{\forestmathresult}% + \let\pgfmathpostparse\forest@temp@pgfmathpostparse + \forestrlet{aggregate result}\pgfmathresult } \pgfmathdeclarefunction{strequal}{2}{% \ifstrequal{#1}{#2}{\def\pgfmathresult{1}}{\def\pgfmathresult{0}}% @@ -3038,28 +4421,32 @@ \forest@forthis{% \forest@nameandgo{#1}% \forest@compute@minmax@ls{#2}% - \pgfmathsetmacro\pgfmathresult{\forestove{min@s}}% + \edef\forest@temp{\forestove{min@s}}% + \edef\pgfmathresult{\expandafter\Pgf@geT\forest@temp}% }% } \pgfmathdeclarefunction{min_l}{2}{% #1 = node, #2 = context node (for growth rotation) \forest@forthis{% \forest@nameandgo{#1}% \forest@compute@minmax@ls{#2}% - \pgfmathsetmacro\pgfmathresult{\forestove{min@l}}% + \edef\forest@temp{\forestove{min@l}}% + \edef\pgfmathresult{\expandafter\Pgf@geT\forest@temp}% }% } \pgfmathdeclarefunction{max_s}{2}{% #1 = node, #2 = context node (for growth rotation) \forest@forthis{% \forest@nameandgo{#1}% \forest@compute@minmax@ls{#2}% - \pgfmathsetmacro\pgfmathresult{\forestove{max@s}}% + \edef\forest@temp{\forestove{max@s}}% + \edef\pgfmathresult{\expandafter\Pgf@geT\forest@temp}% }% } \pgfmathdeclarefunction{max_l}{2}{% #1 = node, #2 = context node (for growth rotation) \forest@forthis{% \forest@nameandgo{#1}% \forest@compute@minmax@ls{#2}% - \pgfmathsetmacro\pgfmathresult{\forestove{max@l}}% + \edef\forest@temp{\forestove{max@l}}% + \edef\pgfmathresult{\expandafter\Pgf@geT\forest@temp}% }% } \def\forest@compute@minmax@ls#1{% #1 = nodewalk; in the context of which node? @@ -3067,7 +4454,7 @@ \pgftransformreset \forest@forthis{% \forest@nameandgo{#1}% - \pgftransformrotate{-\forestove{grow}}% + \forest@pgfqtransformrotate{-\forestove{grow}}% }% \forestoget{min x}\forest@temp@minx \forestoget{min y}\forest@temp@miny @@ -3116,10 +4503,10 @@ \forest@forthis{% \forest@nameandgo{#1}% \ifnum\forest@cn=0 - \def\pgfmathresult{0pt}% + \def\pgfmathresult{0}% \else \forestoget{#2}\forest@temp - \pgfmathparse{+\forest@temp}% + \edef\pgfmathresult{\expandafter\Pgf@geT\forest@temp}% \fi }% } @@ -3129,8 +4516,7 @@ \ifnum\forest@cn=0 \def\pgfmathresult{0}% \else - \forestoget{#2}\forest@temp - \pgfmathtruncatemacro\pgfmathresult{\forest@temp}% + \forestoget{#2}\pgfmathresult \fi }% } @@ -3171,21 +4557,30 @@ \def\forest@nodewalk@config@history@inherited@before{} \let\forest@nodewalk@config@history@inherited@after\forest@nodewalk@config@history@independent@after \def\forest@nodewalk#1#2{% #1 = nodewalk, #2 = every step keylist - \def\forest@nodewalk@config@everystep@method{independent}% - \def\forest@nodewalk@config@history@method{independent}% - \def\forest@nodewalk@config@oninvalid{inherited}% - \forest@saveandrestoremacro\forest@nodewalk@oninvalid{% - \forest@Nodewalk{#1}{#2}% - }% + \forest@configured@nodewalk{independent}{independent}{inherited}{#1}{#2}% } +\def\forest@configured@nodewalk#1#2#3#4#5{% + % #1 = every step method, #2 = history method, #3 = on invalid + % #4 = nodewalk, #5 = every step keylist + \def\forest@nodewalk@config@everystep@method{#1}% + \def\forest@nodewalk@config@history@method{#2}% + \def\forest@nodewalk@config@oninvalid{#3}% + \forest@Nodewalk{#4}{#5}% +} +\def\forest@nodewalk@oninvalid@inherited@text{inherited} \def\forest@Nodewalk#1#2{% #1 = nodewalk, #2 = every step keylist + \ifx\forest@nodewalk@config@oninvalid\forest@nodewalk@oninvalid@inherited@text + \edef\forest@nodewalk@config@oninvalid{\forest@nodewalk@oninvalid}% + \fi \edef\forest@marshal{% \noexpand\pgfqkeys{/forest/nodewalk}{\unexpanded{#1}}% \csname forest@nodewalk@config@everystep@\forest@nodewalk@config@everystep@method @after\endcsname \csname forest@nodewalk@config@history@\forest@nodewalk@config@history@method @after\endcsname + \edef\noexpand\forest@nodewalk@oninvalid{\forest@nodewalk@oninvalid}% }% \csname forest@nodewalk@config@everystep@\forest@nodewalk@config@everystep@method @before\endcsname{#2}% \csname forest@nodewalk@config@history@\forest@nodewalk@config@history@method @before\endcsname + \edef\forest@nodewalk@oninvalid{\forest@nodewalk@config@oninvalid}% \forest@nodewalk@fakefalse \forest@marshal } @@ -3205,25 +4600,27 @@ \def\forest@nodewalk@oninvalid{error} \def\forest@nodewalk@makestep{% \ifnum\forest@cn=0 - \csname forest@nodewalk@makestep@oninvalid@\forest@nodewalk@config@oninvalid\endcsname + \csname forest@nodewalk@makestep@oninvalid@\forest@nodewalk@oninvalid\endcsname \else \forest@nodewalk@makestep@ \fi } -\def\forest@nodewalk@makestep@oninvalid@step{\forest@nodewalk@makestep@} +\csdef{forest@nodewalk@makestep@oninvalid@error if real}{\ifforest@nodewalk@fake\expandafter\forest@nodewalk@makestep@\else\expandafter\forest@nodewalk@makestep@oninvalid@error\fi} +\csdef{forest@nodewalk@makestep@oninvalid@last valid}{% + \forest@nodewalk@tolastvalid + \ifforestdebugnodewalks\forest@nodewalk@makestep@invalidtolastvalid@debug\fi}% \def\forest@nodewalk@makestep@oninvalid@error{\PackageError{forest}{nodewalk stepped to the invalid node\MessageBreak nodewalk stack: "\forest@nodewalk@currentstepname"}{}}% \let\forest@nodewalk@makestep@oninvalid@fake\relax \def\forest@nodewalk@makestep@oninvalid@compatfake{% - \forest@deprecated{last step in stack "\forest@nodewalk@currentstepname", which stepped on an invalid node; enabled by "compat=ignoreinvalidsteps". Use "on invalid={fake}{...}" or "for Nodewalk={on invalid=fake}{...}{...}" instead.}% + \forest@deprecated{last step in stack "\forest@nodewalk@currentstepname", which stepped on an invalid node; enabled by "compat=1.0-forstep". Use "on invalid={fake}{...}" or "for Nodewalk={on invalid=fake}{...}{...}" instead.}% }% -\def\forest@nodewalk@makestep@oninvalid@inherited{\csname forest@nodewalk@makestep@oninvalid@\forest@nodewalk@oninvalid\endcsname} \def\forest@nodewalk@makestep@{% + \ifforestdebugnodewalks\forest@nodewalk@makestep@debug\fi \ifforest@nodewalk@fake \else \edef\forest@nodewalk@n{\number\numexpr\forest@nodewalk@n+1}% \epreto\forest@nodewalk@historyback{\forest@cn,}% \def\forest@nodewalk@historyforward{0,}% - \ifforestdebugnodewalks\forest@nodewalk@makestep@debug\fi \forest@process@keylist@register{every step}% \fi } @@ -3232,6 +4629,11 @@ \noexpand\typeout{\ifforest@nodewalk@fake fake \fi "\forest@nodewalk@currentstepname" step to node id=\forest@cn, content=\forestoption{content}}% }\forest@marshal }% +\def\forest@nodewalk@makestep@invalidtolastvalid@debug{% + \edef\forest@marshal{% + \noexpand\typeout{\ifforest@nodewalk@fake fake \fi "\forest@nodewalk@currentstepname" step to invalid node, (fake) return to last valid id=\forest@cn, content=\forestoption{content}}% + }\forest@marshal +}% \def\forest@handlers@savecurrentpath{% \edef\pgfkeyscurrentkey{\pgfkeyscurrentpath}% \let\forest@currentkey\pgfkeyscurrentkey @@ -3336,6 +4738,8 @@ {\noexpand\forest@forstepwrapper{#1\ifnum\forest@nodewalkstephandler@nargs>0=\fi\forest@util@nargs{####}{\number\numexpr\forest@nodewalkstephandler@nargs}{0}}{####\number\numexpr\forest@nodewalkstephandler@nargs+1}}, }% \fi\fi + % Uncomment this to collect a list of for-based spatial propagators + %\appto\bigbadforlist{[#1]}% \fi }, } @@ -3345,7 +4749,7 @@ }}, } \def\forest@forstepwrapper#1#2{\forest@forthis{\forest@nodewalk{#1}{#2}}} -\def\forest@util@nargs#1#2#3{% #1 = prefix (#, ##, ...), #2 = n args, #3=start; returns {#start}{#start+1}...{#start+n} +\def\forest@util@nargs#1#2#3{% #1 = prefix (#, ##, ...), #2 = n args, #3=start; returns {#start+1}...{#start+n} \ifnum#2>0 {#1\number\numexpr#3+1}\fi \ifnum#2>1 {#1\number\numexpr#3+2}\fi \ifnum#2>2 {#1\number\numexpr#3+3}\fi @@ -3357,7 +4761,11 @@ \ifnum#2>8 {#1\number\numexpr#3+9}\fi } \def\forest@nodewalk@start@oninvalid@fake#1{} -\def\forest@nodewalk@start@oninvalid@real#1{} +\def\forest@nodewalk@start@oninvalid@compatfake#1{% + \forest@deprecated{last step in stack "\forest@nodewalk@currentstepname", which started from an invalid node; enabled by "compat=1.0-forstep". Use "on invalid={fake}{...}" or "for Nodewalk={on invalid=fake}{...}{...}" instead.}% +}% +\let\forest@nodewalk@start@oninvalid@errorifreal\forest@nodewalk@start@oninvalid@fake % the step will be to an invalid node anyway +\let\forest@nodewalk@start@oninvalid@lastvalid\forest@nodewalk@start@oninvalid@fake \def\forest@nodewalk@start@oninvalid@error#1{\PackageError{forest}{nodewalk step "#1" cannot start at the invalid node}{}} \forestset{ define long step={current}{autostep}{}, @@ -3403,21 +4811,21 @@ }, define long step={next leaf}{style,strip fake steps=false}{group={do until={n_children()==0}{next node}}}, define long step={previous leaf}{style,strip fake steps=false}{group={do until={n_children()==0}{previous node}}}, - define long step={next on tier}{autostep}{% + define long step={next on tier}{autostep,n args=1}{% \def\forest@temp{#1}% \ifx\forest@temp\pgfkeysnovalue@text \forestoget{tier}\forest@nodewalk@giventier \else \def\forest@nodewalk@giventier{#1}% \fi - \edef\forest@cn{\forest@node@linearnextnotdescendantid}% + \edef\forest@cn{\forest@node@linearnextid}% \safeloop - \forestoget{tier}\forest@nodewalk@tier - \unless\ifx\forest@nodewalk@tier\forest@nodewalk@giventier + \forest@nodewalk@gettier + \ifforest@temp \edef\forest@cn{\forest@node@linearnextid}% \saferepeat }, - define long step={previous on tier}{autostep}{% + define long step={previous on tier}{autostep,n args=1}{% \def\forest@temp{#1}% \ifx\forest@temp\pgfkeysnovalue@text \forestoget{tier}\forest@nodewalk@giventier @@ -3426,10 +4834,24 @@ \fi \safeloop \edef\forest@cn{\forest@node@linearpreviousid}% - \forestoget{tier}\forest@nodewalk@tier - \unless\ifx\forest@nodewalk@tier\forest@nodewalk@giventier + \forest@nodewalk@gettier + \ifforest@temp \saferepeat }, + TeX={% + \def\forest@nodewalk@gettier{% + \ifnum\forest@cn=0 + \forest@tempfalse + \else + \forestoget{tier}\forest@temp + \ifx\forest@temp\forest@nodewalk@giventier + \forest@tempfalse + \else + \forest@temptrue + \fi + \fi + }% + }, % define long step={root}{autostep,must start at valid node=false}{% \edef\forest@cn{\forest@node@rootid}}, @@ -3439,7 +4861,7 @@ define long step={origin}{autostep,must start at valid node=false}{\edef\forest@cn{\forest@nodewalk@origin}}, % define long step={n}{autostep,n args=1}{% - \pgfmathtruncatemacro\forest@temp@n{#1}% + \forestmathtruncatemacro\forest@temp@n{#1}% \edef\forest@cn{\forest@node@nthchildid{\forest@temp@n}}% }, define long step={n}{autostep,make for=false,n args=1}{% @@ -3449,19 +4871,19 @@ \ifx\forest@nodewalk@temp\pgfkeysnovalue@text \edef\forest@cn{\forestove{@next}}% \else - \pgfmathtruncatemacro\forest@temp@n{#1}% + \forestmathtruncatemacro\forest@temp@n{#1}% \edef\forest@cn{\forest@node@nthchildid{\forest@temp@n}}% \fi }, define long step={n'}{autostep,n args=1}{% - \pgfmathtruncatemacro\forest@temp@n{#1}% + \forestmathtruncatemacro\forest@temp@n{#1}% \edef\forest@cn{\forest@node@nbarthchildid{\forest@temp@n}}% }, define long step={to tier}{autostep,n args=1}{% \def\forest@nodewalk@giventier{#1}% \safeloop - \forestoget{tier}\forest@nodewalk@tier - \unless\ifx\forest@nodewalk@tier\forest@nodewalk@giventier + \forest@nodewalk@gettier + \ifforest@temp \forestoget{@parent}\forest@cn \saferepeat }, @@ -3478,45 +4900,35 @@ \def\forest@nodewalk@config@everystep@method{independent}% \def\forest@nodewalk@config@history@method{shared}% \def\forest@nodewalk@config@oninvalid{inherited}% - \forest@saveandrestoremacro\forest@nodewalk@oninvalid{% - \pgfqkeys{/forest/nodewalk@config}{#1}% - \forest@Nodewalk{#2}{#3}% - }% + \pgfqkeys{/forest/nodewalk@config}{#1}% + \forest@Nodewalk{#2}{#3}% }, define long step={nodewalk}{n args=2,@bare}{% #1 = nodewalk, #2 = every step \forest@nodewalk{#1}{#2}% }, - define long step={nodewalk'}{n args=1,@bare}{% #1 = nodewalk, #2 = every step - \def\forest@nodewalk@config@everystep@method{inherited}% - \def\forest@nodewalk@config@history@method{independent}% - \def\forest@nodewalk@config@oninvalid{inherited}% - \forest@saveandrestoremacro\forest@nodewalk@oninvalid{% - \forest@Nodewalk{#1}{}% - }% + define long step={nodewalk'}{n args=1,@bare}{% #1 = nodewalk + \forest@configured@nodewalk{inherited}{independent}{inherited}{#1}{}% }, - % these must be defined explicitely, as prefix "for" normally introduces the every-step keylist - for nodewalk/.code 2 args={% + % these "for ..." keys must be defined explicitely + % (and copied into node keyspace manually), + % as prefix "for" normally introduces the every-step keylist + define long step={for nodewalk}{n args=2,@bare}{% #1 = nodewalk, #2 = every step \forest@forthis{\forest@nodewalk{#1}{#2}}}, - for nodewalk'/.code={% - \def\forest@nodewalk@config@everystep@method{inherited}% - \def\forest@nodewalk@config@history@method{independent}% - \def\forest@nodewalk@config@oninvalid{inherited}% - \forest@saveandrestoremacro\forest@nodewalk@oninvalid{% - \forest@forthis{\forest@Nodewalk{#1}{}}% + define long step={for nodewalk'}{n args=1,@bare}{% #1 = nodewalk + \forest@forthis{% + \forest@configured@nodewalk{inherited}{independent}{inherited}{#1}{}% }% }, - for Nodewalk/.code n args=3{% #1 = config, #2 = nodewalk, #3 = every-step - \def\forest@nodewalk@config@everystep@method{inherited}% - \def\forest@nodewalk@config@history@method{independent}% + define long step={for Nodewalk}{n args=3,@bare}{% #1 = config, #2 = nodewalk, #3 = every-step + \def\forest@nodewalk@config@everystep@method{independent}% + \def\forest@nodewalk@config@history@method{shared}% \def\forest@nodewalk@config@oninvalid{inherited}% - \forest@saveandrestoremacro\forest@nodewalk@oninvalid{% - \pgfqkeys{/forest/nodewalk@config}{#1}% - \forest@forthis{\forest@Nodewalk{#2}{#3}}% - }% + \pgfqkeys{/forest/nodewalk@config}{#1}% + \forest@forthis{\forest@Nodewalk{#2}{#3}}% }, - copy command key={/forest/for nodewalk}{/forest/nodewalk/for nodewalk}, - copy command key={/forest/for nodewalk'}{/forest/nodewalk/for nodewalk'}, - copy command key={/forest/for Nodewalk}{/forest/nodewalk/for Nodewalk}, + copy command key={/forest/nodewalk/Nodewalk}{/forest/Nodewalk}, + copy command key={/forest/nodewalk/for nodewalk}{/forest/for nodewalk}, + copy command key={/forest/nodewalk/for Nodewalk}{/forest/for Nodewalk}, declare keylist register=every step, every step'={}, %%% begin nodewalk config @@ -3536,23 +4948,25 @@ on@invalid/.is choice, on@invalid/error/.code={}, on@invalid/fake/.code={}, - on@invalid/step/.code={}, + on@invalid/error if real/.code={}, + on@invalid/last valid/.code={}, on@invalid/inherited/.code={}, on invalid/.store in=\forest@nodewalk@config@oninvalid, on invalid/.prefix style={on@invalid=#1}, %%% end nodewalk config } +\newtoks\forest@nodewalk@branch@toks \forestset{ declare toks register=branch@temp@toks, branch@temp@toks={}, declare keylist register=branched@nodewalk, branched@nodewalk={}, - define long step={branch}{n args=1,@bare,style}{@branch={#1}{branch@build@realstep,branch@build@fakestep}}, - define long step={branch'}{n args=1,@bare,style}{@branch={#1}{branch@build@realstep}}, + define long step={branch}{n args=1,@bare,make for,style}{@branch={#1}{branch@build@realstep,branch@build@fakestep}}, + define long step={branch'}{n args=1,@bare,make for,style}{@branch={#1}{branch@build@realstep}}, @branch/.style 2 args={% save and restore register={branched@nodewalk}{ branch@temp@toks={}, - split/.process args={r}{#1}{,}{#2}, + split/.process={r}{#1}{,}{#2}, branch@temp@style/.style/.register=branch@temp@toks, branch@temp@style, branch@temp@style/.style/.register=branched@nodewalk, @@ -3568,7 +4982,7 @@ branch@temp@toks/.expanded={for nodewalk={\unexpanded{#1}}{ \forestregister{branch@temp@toks}}}, }, - define long step={group}{autostep}{\forest@go{#1}}, + define long step={group}{autostep,n args=1}{\forest@go{#1}}, nodewalk/fake/.code={% \forest@saveandrestoreifcs{forest@nodewalk@fake}{% \forest@nodewalk@faketrue @@ -3583,7 +4997,7 @@ }, declare keylist register=filtered@nodewalk, filtered@nodewalk={}, - define long step={filter}{n args=2,@bare,style}{% #1 = nodewalk, #2 = condition + define long step={filter}{n args=2,@bare,make for,style}{% #1 = nodewalk, #2 = condition save and restore register={filtered@nodewalk}{ filtered@nodewalk'={}, Nodewalk=% @@ -3592,12 +5006,13 @@ {if={#2}{filtered@nodewalk+/.expanded={id=\forestoption{id}}}{}}, filtered@nodewalk@style/.style/.register=filtered@nodewalk, filtered@nodewalk@style - } + }, }, on@invalid/.is choice, on@invalid/error/.code={}, on@invalid/fake/.code={}, - on@invalid/step/.code={}, + on@invalid/error if real/.code={}, + on@invalid/last valid/.code={}, on invalid/.code 2 args={% \pgfkeysalso{/forest/on@invalid={#1}}% \forest@saveandrestoremacro\forest@nodewalk@oninvalid{% @@ -3607,38 +5022,54 @@ }, define long step={strip fake steps}{n args=1,@bare}{% \forest@nodewalk@stripfakesteps{\pgfkeysalso{#1}}}, + define long step={unique}{n args=1}{% + \begingroup + \def\forest@nodewalk@unique@temp{}% + \forest@nodewalk{#1}{% + TeX={% + \forestoget{unique@visited}\forest@temp + \ifx\forest@temp\relax + \forestoset{unique@visited}{1}% + \eappto\forest@nodewalk@unique@temp{,id=\forest@cn}% + \fi + }% + }% + \global\let\forest@global@temp\forest@nodewalk@unique@temp + \endgroup + \pgfkeysalsofrom{\forest@global@temp}% + }, define long step={walk back}{n args=1,@bare}{% - \pgfmathtruncatemacro\forest@temp@n{#1}% + \forestmathtruncatemacro\forest@temp@n{#1}% \forest@nodewalk@walklist{\forest@nodewalk@historyforward}{\forest@nodewalk@historyback}{\ifnum\forest@cn=0 0\else1\fi}{\forest@temp@n+\ifnum\forest@cn=0 0\else1\fi}{\let\forest@cn\forest@nodewalk@cn\forest@nodewalk@makestep}% \forest@nodewalk@back@updatehistory }, nodewalk/walk back/.default=1, define long step={jump back}{n args=1,@bare}{% - \pgfmathtruncatemacro\forest@temp@n{(#1)+\ifnum\forest@cn=0 0\else1\fi}% + \forestmathtruncatemacro\forest@temp@n{(#1)+\ifnum\forest@cn=0 0\else1\fi}% \forest@nodewalk@walklist{\forest@nodewalk@historyforward}{\forest@nodewalk@historyback}{\forest@temp@n-1}{\forest@temp@n}{\let\forest@cn\forest@nodewalk@cn\forest@nodewalk@makestep}% \forest@nodewalk@back@updatehistory }, nodewalk/jump back/.default=1, define long step={back}{n args=1,@bare}{% - \pgfmathtruncatemacro\forest@temp@n{#1}% + \forestmathtruncatemacro\forest@temp@n{#1}% \forest@nodewalk@walklist{\forest@nodewalk@historyforward}{\forest@nodewalk@historyback}{\ifnum\forest@cn=0 0\else1\fi}{\forest@temp@n+\ifnum\forest@cn=0 0\else1\fi}{\let\forest@cn\forest@nodewalk@cn\forest@saveandrestoreifcs{forest@nodewalk@fake}{\forest@nodewalk@faketrue\forest@nodewalk@makestep}}% \forest@nodewalk@back@updatehistory }, nodewalk/back/.default=1, define long step={walk forward}{n args=1,@bare}{% - \pgfmathtruncatemacro\forest@temp@n{#1}% + \forestmathtruncatemacro\forest@temp@n{#1}% \forest@nodewalk@walklist{\forest@nodewalk@historyback}{\forest@nodewalk@historyforward}{0}{\forest@temp@n}{\let\forest@cn\forest@nodewalk@cn\forest@nodewalk@makestep}% \forest@nodewalk@forward@updatehistory }, nodewalk/walk forward/.default=1, define long step={jump forward}{n args=1,@bare}{% - \pgfmathtruncatemacro\forest@temp@n{#1}% + \forestmathtruncatemacro\forest@temp@n{#1}% \forest@nodewalk@walklist{\forest@nodewalk@historyback}{\forest@nodewalk@historyforward}{\forest@temp@n-1}{\forest@temp@n}{\let\forest@cn\forest@nodewalk@cn\forest@nodewalk@makestep}% \forest@nodewalk@forward@updatehistory }, nodewalk/jump forward/.default=1, define long step={forward}{n args=1,@bare}{% - \pgfmathtruncatemacro\forest@temp@n{#1}% + \forestmathtruncatemacro\forest@temp@n{#1}% \forest@nodewalk@walklist{\forest@nodewalk@historyback}{\forest@nodewalk@historyforward}{0}{\forest@temp@n}{\let\forest@cn\forest@nodewalk@cn\forest@saveandrestoreifcs{forest@nodewalk@fake}{\forest@nodewalk@faketrue\forest@nodewalk@makestep}}% \forest@nodewalk@forward@updatehistory }, @@ -3691,7 +5122,9 @@ \noexpand\forest@nodewalk@sortlist{\noexpand\forest@nodewalk@historyback}{\noexpand\forest@nodewalk@n-\forest@nodewalk@n}\noexpand\forest@sort@descending }\forest@marshal }, - sort by/.store in=\forest@nodesort@by, + declare keylist register=sort by, + copy command key={/forest/sort by'}{/forest/sort by}, + sort by={}, define long step={save}{n args=2,@bare,make for}{% #1 = name, #2 = nodewalk \forest@forthis{% \forest@nodewalk{#2,TeX={% @@ -3709,6 +5142,21 @@ }\forest@marshal \csedef{forest@nodewalk@saved@#1}{\forest@nodewalk@walklist@walked}% }, + define long step={save append}{style,n args=2,@bare,make for}{% #1 = nodewalk name, #2 = nodewalk + save@append@prepend={#1}{#2}{save}{\cseappto}}, + define long step={save prepend}{style,n args=2,@bare,make for}{% #1 = nodewalk name, #2 = nodewalk + save@append@prepend={#1}{#2}{save}{\csepreto}}, + define long step={walk and save append}{style,n args=2,@bare,make for}{% #1 = nodewalk name, #2 = nodewalk + save@append@prepend={#1}{#2}{walk and save}{\cseappto}}, + define long step={walk and save prepend}{style,n args=2,@bare,make for}{% #1 = nodewalk name, #2 = nodewalk + save@append@prepend={#1}{#2}{walk and save}{\csepreto}}, + nodewalk/save@append@prepend/.code n args=4{% + % #1 = nodewalk name, #2 = nodewalk + % #3 = "(walk and) save" #4 = \cseappto/\csepreto + \pgfkeysalso{#3={@temp}{#2}}% + \letcs\forest@temp{forest@nodewalk@saved@@temp}% + #4{forest@nodewalk@saved@#1}{\expandonce{\forest@temp}}% + }, nodewalk/save history/.code 2 args={% #1 = back, forward \csedef{forest@nodewalk@saved@#1}{\forest@nodewalk@historyback}% \csedef{forest@nodewalk@saved@#2}{\forest@nodewalk@historyforward}% @@ -3799,12 +5247,7 @@ \let\forest@nodewalk@historyback\forest@nodewalk@walklist@walked } \def\forest@go#1{% - \def\forest@nodewalk@config@everystep@method{independent}% - \def\forest@nodewalk@config@history@method{inherited}% - \def\forest@nodewalk@config@oninvalid{inherited}% - \forest@saveandrestoremacro\forest@nodewalk@oninvalid{% - \forest@Nodewalk{#1}{}% - }% + \forest@configured@nodewalk{independent}{inherited}{inherited}{#1}{}% } \def\forest@csvlist@getfirst@#1{% assuming that the list is nonempty and finishes with a comma \forest@csvlist@getfirst@@#1\forest@csvlist@getfirst@@} @@ -3852,7 +5295,7 @@ \expandafter\forest@csvlist@getfirstrest@\expandafter{\forest@nodewalksort@list}\forest@nodewalksort@cn\forest@nodewalksort@list \csedef{forest@nodesort@\safeloopn}{\forest@nodewalksort@cn}% \saferepeat - \edef\forest@nodesort@sortkey{\forest@nodesort@by}% + \forestrget{sort by}\forest@nodesort@sortkey \forest@sort\forest@nodesort@cmpnodes\forest@nodesort@let#2{1}{#1}% \def\forest@nodewalksort@sorted{}% \safeloop @@ -3936,7 +5379,7 @@ % #2 = max index in list (start with 1) % #3 = min/max = ascending/descending = </> % #4 = how many results? 1 = {\forest@nodewalk@minmax@node,}, all={\forest@nodewalk@minmax@nodes}, walk in history={} - \edef\forest@nodesort@sortkey{\forest@nodesort@by}% + \forestrget{sort by}\forest@nodesort@sortkey \edef\forest@nodewalk@minmax@N{\number\numexpr#2}% \edef\forest@nodewalk@minmax@n{}% \edef\forest@nodewalk@minmax@list{#1}% @@ -4146,7 +5589,7 @@ define long step={descendants breadth-first}{}{\forest@node@foreach@breadthfirst{0}{\forest@nodewalk@makestep}}, define long step={descendants breadth-first reversed}{}{\forest@node@foreach@breadthfirst@reversed{0}{\forest@nodewalk@makestep}}, define long step={level}{n args=1}{% - \pgfmathtruncatemacro\forest@temp{#1}% + \forestmathtruncatemacro\forest@temp{#1}% \edef\forest@marshal{% \noexpand\forest@node@foreach@breadthfirst {\forest@temp}% @@ -4154,7 +5597,7 @@ }\forest@marshal }, define long step={level>}{n args=1}{% - \pgfmathtruncatemacro\forest@temp{#1}% + \forestmathtruncatemacro\forest@temp{#1}% \edef\forest@marshal{% \noexpand\forest@node@foreach@breadthfirst {-1}% @@ -4162,8 +5605,7 @@ }\forest@marshal }, define long step={level<}{n args=1}{% - \pgfmathtruncatemacro\forest@temp{(#1)-1}% - \show\forest@temp + \forestmathtruncatemacro\forest@temp{(#1)-1}% \ifnum\forest@temp=-1 % special case, as \forest@node@foreach@breadthfirst uses level<0 as a signal for unlimited max level \ifnum\forestove{level}=0 @@ -4178,7 +5620,7 @@ \fi }, define long step={level reversed}{n args=1}{% - \pgfmathtruncatemacro\forest@temp{#1}% + \forestmathtruncatemacro\forest@temp{#1}% \edef\forest@marshal{% \noexpand\forest@node@foreach@breadthfirst@reversed {\forest@temp}% @@ -4186,7 +5628,7 @@ }\forest@marshal }, define long step={level reversed>}{n args=1}{% - \pgfmathtruncatemacro\forest@temp{#1}% + \forestmathtruncatemacro\forest@temp{#1}% \edef\forest@marshal{% \noexpand\forest@node@foreach@breadthfirst@reversed {-1}% @@ -4194,7 +5636,7 @@ }\forest@marshal }, define long step={level reversed<}{n args=1}{% - \pgfmathtruncatemacro\forest@temp{(#1)-1}% + \forestmathtruncatemacro\forest@temp{(#1)-1}% \edef\forest@marshal{% \noexpand\forest@node@foreach@breadthfirst@reversed {\forest@temp}% @@ -4203,7 +5645,7 @@ }, % define long step={relative level}{n args=1}{% - \pgfmathtruncatemacro\forest@temp{(#1)+\forestove{level}}% + \forestmathtruncatemacro\forest@temp{(#1)+\forestove{level}}% \edef\forest@marshal{% \noexpand\forest@node@foreach@breadthfirst {\forest@temp}% @@ -4211,7 +5653,7 @@ }\forest@marshal }, define long step={relative level>}{n args=1}{% - \pgfmathtruncatemacro\forest@temp{(#1)+\forestove{level}}% + \forestmathtruncatemacro\forest@temp{(#1)+\forestove{level}}% \edef\forest@marshal{% \noexpand\forest@node@foreach@breadthfirst {-1}% @@ -4219,7 +5661,7 @@ }\forest@marshal }, define long step={relative level<}{n args=1}{% - \pgfmathtruncatemacro\forest@temp{(#1)+\forestove{level}-1}% + \forestmathtruncatemacro\forest@temp{(#1)+\forestove{level}-1}% \edef\forest@marshal{% \noexpand\forest@node@foreach@breadthfirst {\forest@temp}% @@ -4227,7 +5669,7 @@ }\forest@marshal }, define long step={relative level reversed}{n args=1}{% - \pgfmathtruncatemacro\forest@temp{(#1)+\forestove{level}}% + \forestmathtruncatemacro\forest@temp{(#1)+\forestove{level}}% \edef\forest@marshal{% \noexpand\forest@node@foreach@breadthfirst@reversed {\forest@temp}% @@ -4235,7 +5677,7 @@ }\forest@marshal }, define long step={relative level reversed>}{n args=1}{% - \pgfmathtruncatemacro\forest@temp{(#1)+\forestove{level}}% + \forestmathtruncatemacro\forest@temp{(#1)+\forestove{level}}% \edef\forest@marshal{% \noexpand\forest@node@foreach@breadthfirst@reversed {-1}% @@ -4243,13 +5685,26 @@ }\forest@marshal }, define long step={relative level reversed<}{n args=1}{% - \pgfmathtruncatemacro\forest@temp{(#1)+\forestove{level}-1}% + \forestmathtruncatemacro\forest@temp{(#1)+\forestove{level}-1}% \edef\forest@marshal{% \noexpand\forest@node@foreach@breadthfirst@reversed {\forest@temp}% {\noexpand\forest@nodewalk@makestep}% }\forest@marshal }, + define long step={leaves}{}{% + \forest@node@foreach{% + \ifnum\forestove{n children}=0 + \forest@nodewalk@makestep + \fi + }% + }, + define long step={-level}{n args=1,style}{% + unique={branch={leaves,{group={repeat={#1}{parent}}}}} + }, + define long step={-level'}{n args=1,style}{% + unique={on invalid={fake}{branch={leaves,{group={repeat={#1}{parent}}}}}} + }, define long step={children}{}{\forest@node@foreachchild{\forest@nodewalk@makestep}}, define long step={children reversed}{}{\forest@node@foreachchild@reversed{\forest@nodewalk@makestep}}, define long step={current and following siblings}{}{\forest@node@@forselfandfollowingsiblings{\forest@nodewalk@makestep}}, @@ -4327,7 +5782,13 @@ \def\forest@saveandrestoreifcs#1#2{% #1 = the if cs to save before and restore after processing code in #2 \edef\forest@marshal{% \unexpanded{#2}% - \ifbool{#1}{\noexpand\setbool{#1}{true}}{\noexpand\setbool{#1}{false}} + \ifbool{#1}{\noexpand\setbool{#1}{true}}{\noexpand\setbool{#1}{false}}% + }\forest@marshal +} +\def\forest@globalsaveandrestoreifcs#1#2{% #1 = the if cs to save before and restore after processing code in #2 + \edef\forest@marshal{% + \unexpanded{#2}% + \ifbool{#1}{\global\noexpand\setbool{#1}{true}}{\global\noexpand\setbool{#1}{false}}% }\forest@marshal } \def\forest@saveandrestoretoks#1#2{% #1 = the toks to save before and restore after processing code in #2 @@ -4344,7 +5805,7 @@ } \forestset{ save and restore register/.code 2 args={% - \forest@saveandrestoreregister{filter@ed}{% + \forest@saveandrestoreregister{#1}{% \pgfkeysalso{#2}% }% }, @@ -4455,21 +5916,16 @@ replace by''/.code={\forest@replaceby@code{#1}{insert after''}}, sort/.code={% \eapptotoks\forest@do@dynamics{% - \noexpand\forest@nodesort - \noexpand\forest@sort@ascending - {\forest@cn}% - {\expandonce{\forest@nodesort@by}}% + \def\noexpand\forest@nodesort@sortkey{\forestrv{sort by}}% + \noexpand\forest@nodesort\noexpand\forest@sort@ascending{\forest@cn} }% }, sort'/.code={% \eapptotoks\forest@do@dynamics{% - \noexpand\forest@nodesort - \noexpand\forest@sort@descending - {\forest@cn}% - {\expandonce{\forest@nodesort@by}}% + \def\noexpand\forest@nodesort@sortkey{\forestrv{sort by}}% + \noexpand\forest@nodesort\noexpand\forest@sort@descending{\forest@cn} }% }, - sort by/.store in=\forest@nodesort@by, } \def\forest@replaceby@code#1#2{%#1=node spec,#2=insert after[']['] \ifnum\forestove{@parent}=0 @@ -4485,10 +5941,9 @@ }% \fi } -\def\forest@nodesort#1#2#3{% #1 = direction, #2 = parent node, #3 = sort key +\def\forest@nodesort#1#2{% #1 = direction, #2 = parent node \ifforestdebugdynamics\forestdebug@dynamics{before sorting children of #2}\fi - \def\forest@nodesort@sortkey{#3}% - \forest@fornode{#2}{\forest@nodesort@#1}% + \forest@fornode{#2}{\forest@nodesort@#1}% \ifforestdebugdynamics\forestdebug@dynamics{after sorting children of #2}\fi } \def\forest@nodesort@#1{% @@ -4516,29 +5971,53 @@ \forest@loop \ifnum\c@pgf@counta<\forest@nodesort@n\relax \advance\c@pgf@counta 1 - \edef\temp{\csname forest@nodesort@\the\c@pgf@counta\endcsname}% \forest@node@append{\csname forest@nodesort@\the\c@pgf@counta\endcsname}% \forest@repeat } \def\forest@nodesort@cmpnodes#1#2{% - \global\let\forest@nodesort@cmpresult\forest@sort@cmp@eq - \foreach \forest@temp@pgfmath in \forest@nodesort@sortkey {% - \forest@fornode{\csname forest@nodesort@#1\endcsname}{% - \pgfmathparse{\forest@temp@pgfmath}\global\let\forest@global@tempa\pgfmathresult}% - \forest@fornode{\csname forest@nodesort@#2\endcsname}{% - \pgfmathparse{\forest@temp@pgfmath}\global\let\forest@global@tempb\pgfmathresult}% - \ifdim\forest@global@tempa pt<\forest@global@tempb pt - \global\let\forest@nodesort@cmpresult\forest@sort@cmp@lt - \breakforeach - \else - \ifdim\forest@global@tempa pt>\forest@global@tempb pt - \global\let\forest@nodesort@cmpresult\forest@sort@cmp@gt - \breakforeach - \fi + \expandafter\forest@nodesort@cmpnodes@\forest@nodesort@sortkey,\forest@END{#1}{#2}% +} +\def\forest@nodesort@cmpnodes@#1,#2\forest@END#3#4{% + % #1=process ins+arg for this dimension, #2=for next dimensions + % #3, #4 = node ids + {% + \forest@fornode{\csname forest@nodesort@#3\endcsname}{% + \forestmathsetmacro\forest@nodesort@resulta{#1}% + }% + \forest@fornode{\csname forest@nodesort@#4\endcsname}{% + \forestmathsetmacro\forest@nodesort@resultb{#1}% + }% + \ifx\forestmathresulttype\forestmathtype@generic + \forest@cmp@error{\forest@nodesort@resulta}{\forest@nodesort@resultb}% \fi + \edef\forest@temp{% + \noexpand\forest@nodesort@cmp + {\expandonce{\forest@nodesort@resulta}}% + {\expandonce{\forest@nodesort@resultb}}% + }% + \xdef\forest@global@temp{\forest@temp}% }% - \forest@nodesort@cmpresult -} + \if=\forest@global@temp + \let\forest@next\forest@nodesort@cmpnodes@ + \else + \let\forest@next\forest@nodesort@cmpnodes@finish + \fi + \ifstrempty{#2}{\let\forest@next\forest@nodesort@cmpnodes@finish}{}% + \forest@next#2\forest@END{#3}{#4}% +} +\def\forest@nodesort@cmpnodes@finish#1\forest@END#2#3{% + \let\forest@sort@cmp@result\forest@global@temp +} +\def\forest@nodesort@cmp{\csname fRsT@nsc@\forestmathresulttype\endcsname} +\def\fRsT@nsc@#1{\csname fRsT@nsc@#1\endcsname} +\def\fRsT@nsc@n#1#2{\ifnum#1<#2 <\else\ifnum#1=#2 =\else>\fi\fi} +\def\fRsT@nsc@d#1#2{\ifdim#1<#2 <\else\ifdim#1=#2 =\else>\fi\fi} +\def\fRsT@nsc@P#1#2{\ifdim#1pt<#2pt <\else\ifdim#1pt=#2pt =\else>\fi\fi} +\def\fRsT@nsc@t#1#2{\csname fRsT@nsc@\pdfstrcmp{#1}{#2}\endcsname} +\def\fRsT@nsc@T#1#2{\csname fRsT@nsc@\pdfstrcmp{#2}{#1}\endcsname} +\csdef{fRsT@nsc@-1}{<} +\csdef{fRsT@nsc@0}{=} +\csdef{fRsT@nsc@1}{>} \def\forest@nodesort@let#1#2{% \csletcs{forest@nodesort@#1}{forest@nodesort@#2}% } @@ -4596,9 +6075,16 @@ declare keylist={before computing xy}{}, declare keylist={before drawing tree}{}, declare keylist={delay}{}, - delay n/.style 2 args={if={#1==0}{#2}{delay@n={#1}{#2}}}, - delay@n/.style 2 args={ - if={#1==1}{delay={#2}}{delay={delay@n/.process args={P}{#1-1}{#2}}} + delay n/.code 2 args={% + \forestmathsetcount\forest@temp@count{#1}% + \pgfkeysalso{delay n'={\forest@temp@count}{#2}}% + }, + delay n'/.code 2 args={ + \ifnum#1=0 + \pgfkeysalso{#2}% + \else + \pgfkeysalso{delay={delay n'/.expand once=\expandafter{\number\numexpr#1-1\relax}{#2}}}% + \fi }, if have delayed/.style 2 args={if have delayed'={processing order}{#1}{#2}}, if have delayed'/.code n args=3{% @@ -5076,7 +6562,7 @@ \def\forest@pack@pgfpoint@childsposition#1{% {% \pgftransformreset - \pgftransformrotate{\forestove{grow}}% + \forest@pgfqtransformrotate{\forestove{grow}}% \forest@fornode{#1}{% \pgfpointtransformed{\pgfqpoint{\forestove{l}}{\forestove{s}}}% }% @@ -5085,7 +6571,7 @@ \def\forest@pack@pgfpoint@positioningrow#1{% {% \pgftransformreset - \pgftransformrotate{#1}% + \forest@pgfqtransformrotate{#1}% \pgfpointtransformed{\pgfqpoint{\forestove{l}}{\forestove{s}}}% }% } @@ -5102,7 +6588,7 @@ {% \edef\forest@temp@child{\forest@node@nornbarthchildid{\forestove{calign primary child}}}% \pgftransformreset - \pgftransformrotate{\forestove{grow}}% + \forest@pgfqtransformrotate{\forestove{grow}}% \pgfpointtransformed{\pgfqpoint{\forestOve{\forest@temp@child}{l}}{\forestOve{\forest@temp@child}{s}}}% \pgf@xa=\pgf@x\relax\pgf@ya=\pgf@y\relax \forest@Pointanchor{\forest@temp@child}{child anchor}% @@ -5111,7 +6597,7 @@ \advance\pgf@xa-\pgf@x\relax\advance\pgf@ya-\pgf@y\relax \edef\forest@marshal{% \noexpand\pgftransformreset - \noexpand\pgftransformrotate{-\forestove{grow}}% + \noexpand\forest@pgfqtransformrotate{-\forestove{grow}}% \noexpand\pgfpointtransformed{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}% }\forest@marshal }% @@ -5129,7 +6615,7 @@ \edef\forest@temp@firstchild{\forest@node@nornbarthchildid{\forestove{calign primary child}}}% \edef\forest@temp@secondchild{\forest@node@nornbarthchildid{\forestove{calign secondary child}}}% \pgftransformreset - \pgftransformrotate{\forestove{grow}}% + \forest@pgfqtransformrotate{\forestove{grow}}% \pgfpointtransformed{\pgfqpoint{\forestOve{\forest@temp@firstchild}{l}}{\forestOve{\forest@temp@firstchild}{s}}}% \pgf@xa=\pgf@x\relax\pgf@ya=\pgf@y\relax \forest@Pointanchor{\forest@temp@firstchild}{child anchor}% @@ -5145,12 +6631,16 @@ \advance\pgf@xa-\pgf@x\relax\advance\pgf@ya-\pgf@y\relax \edef\forest@marshal{% \noexpand\pgftransformreset - \noexpand\pgftransformrotate{-\forestove{grow}}% + \noexpand\forest@pgfqtransformrotate{-\forestove{grow}}% \noexpand\pgfpointtransformed{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}% }\forest@marshal }% \forest@calign@s@shift{\the\dimexpr-\the\pgf@y}% } +\def\forest@edef@strippt#1#2{% + \edef#1{#2}% + \edef#1{\expandafter\Pgf@geT#1}% +} \csdef{forest@calign@fixed angles}{% \ifnum\forestove{n children}>1 \edef\forest@ca@first@child{\forest@node@nornbarthchildid{\forestove{calign primary child}}}% @@ -5161,45 +6651,84 @@ \let\forest@ca@second@child\forest@temp \fi \forestOget{\forest@ca@first@child}{l}\forest@ca@first@l + \edef\forest@ca@first@l{\expandafter\Pgf@geT\forest@ca@first@l}% \forestOget{\forest@ca@second@child}{l}\forest@ca@second@l - \pgfmathsetlengthmacro\forest@ca@desired@s@distance{% - tan(\forestove{calign secondary angle})*\forest@ca@second@l - -tan(\forestove{calign primary angle})*\forest@ca@first@l - }% + \edef\forest@ca@second@l{\expandafter\Pgf@geT\forest@ca@second@l}% + \pgfmathtan@{\forestove{calign secondary angle}}% + \pgfmathmultiply@{\pgfmathresult}{\forest@ca@second@l}% + \let\forest@calign@temp\pgfmathresult + \pgfmathtan@{\forestove{calign primary angle}}% + \pgfmathmultiply@{\pgfmathresult}{\forest@ca@first@l}% + \edef\forest@ca@desired@s@distance{\the\dimexpr + \forest@calign@temp pt-\pgfmathresult pt}% + % \pgfmathsetlengthmacro\forest@ca@desired@s@distance{% + % tan(\forestove{calign secondary angle})*\forest@ca@second@l + % -tan(\forestove{calign primary angle})*\forest@ca@first@l + % }% \forestOget{\forest@ca@first@child}{s}\forest@ca@first@s \forestOget{\forest@ca@second@child}{s}\forest@ca@second@s - \pgfmathsetlengthmacro\forest@ca@actual@s@distance{% + \edef\forest@ca@actual@s@distance{\the\dimexpr \forest@ca@second@s-\forest@ca@first@s}% + %\pgfmathsetlengthmacro\forest@ca@actual@s@distance{% + % \forest@ca@second@s-\forest@ca@first@s}% \ifdim\forest@ca@desired@s@distance>\forest@ca@actual@s@distance\relax \ifdim\forest@ca@actual@s@distance=0pt - \pgfmathsetlength\pgfutil@tempdima{tan(\forestove{calign primary angle})*\forest@ca@second@l}% - \pgfmathsetlength\pgfutil@tempdimb{\forest@ca@desired@s@distance/(\forestove{n children}-1)}% + \pgfmathtan@{\forestove{calign primary angle}}% + \pgfmathmultiply@{\pgfmathresult}{\forest@ca@second@l}% + \pgfutil@tempdima=\pgfmathresult pt + % \pgfmathsetlength\pgfutil@tempdima{tan(\forestove{calign primary angle})*\forest@ca@second@l}% + \pgfutil@tempdimb=\dimexpr + \forest@ca@desired@s@distance/(\forestove{n children}-1)\relax% + %\pgfmathsetlength\pgfutil@tempdimb{\forest@ca@desired@s@distance/(\forestove{n children}-1)}% \forest@node@foreachchild{% \forestoeset{s}{\the\pgfutil@tempdima}% \advance\pgfutil@tempdima\pgfutil@tempdimb }% \def\forest@calign@anchor{0pt}% \else - \pgfmathsetmacro\forest@ca@ratio{% - \forest@ca@desired@s@distance/\forest@ca@actual@s@distance}% + \edef\forest@marshal{\noexpand\pgfmathdivide@ + {\expandafter\Pgf@geT\forest@ca@desired@s@distance}% + {\expandafter\Pgf@geT\forest@ca@actual@s@distance}% + }\forest@marshal + \let\forest@ca@ratio\pgfmathresult + %\pgfmathsetmacro\forest@ca@ratio{% + % \forest@ca@desired@s@distance/\forest@ca@actual@s@distance}% \forest@node@foreachchild{% - \pgfmathsetlengthmacro\forest@temp{\forest@ca@ratio*\forestove{s}}% - \forestolet{s}\forest@temp + \forest@edef@strippt\forest@temp{\forestove{s}}% + \pgfmathmultiply@{\forest@ca@ratio}{\forest@temp}% + \forestoeset{s}{\the\dimexpr\pgfmathresult pt}% + %\pgfmathsetlengthmacro\forest@temp{\forest@ca@ratio*\forestove{s}}% + %\forestolet{s}\forest@temp }% - \pgfmathsetlengthmacro\forest@calign@anchor{% - -tan(\forestove{calign primary angle})*\forest@ca@first@l}% + \pgfmathtan@{\forestove{calign primary angle}}% + \pgfmathmultiply@{\pgfmathresult}{\forest@ca@first@l}% + \edef\forest@calign@anchor{\the\dimexpr-\pgfmathresult pt}% + %\pgfmathsetlengthmacro\forest@calign@anchor{% + % -tan(\forestove{calign primary angle})*\forest@ca@first@l}% \fi \else \ifdim\forest@ca@desired@s@distance<\forest@ca@actual@s@distance\relax - \pgfmathsetlengthmacro\forest@ca@ratio{% - \forest@ca@actual@s@distance/\forest@ca@desired@s@distance}% + \edef\forest@marshal{\noexpand\pgfmathdivide@ + {\expandafter\Pgf@geT\forest@ca@actual@s@distance}% + {\expandafter\Pgf@geT\forest@ca@desired@s@distance}% + }\forest@marshal + \let\forest@ca@ratio\pgfmathresult + %\pgfmathsetlengthmacro\forest@ca@ratio{% + % \forest@ca@actual@s@distance/\forest@ca@desired@s@distance}% \forest@node@foreachchild{% - \pgfmathsetlengthmacro\forest@temp{\forest@ca@ratio*\forestove{l}}% - \forestolet{l}\forest@temp + \forest@edef@strippt\forest@temp{\forestove{l}}% + \pgfmathmultiply@{\forest@ca@ratio}{\forest@temp}% + \forestoeset{l}{\the\dimexpr\pgfmathresult pt}% + %\pgfmathsetlengthmacro\forest@temp{\forest@ca@ratio*\forestove{l}}% + %\forestolet{l}\forest@temp }% \forestOget{\forest@ca@first@child}{l}\forest@ca@first@l - \pgfmathsetlengthmacro\forest@calign@anchor{% - -tan(\forestove{calign primary angle})*\forest@ca@first@l}% + \edef\forest@ca@first@l{\expandafter\Pgf@geT\forest@ca@first@l}% + \pgfmathtan@{\forestove{calign primary angle}}% + \pgfmathmultiply@{\pgfmathresult}{\forest@ca@first@l}% + \edef\forest@calign@anchor{\the\dimexpr-\pgfmathresult pt}% + %\pgfmathsetlengthmacro\forest@calign@anchor{% + % -tan(\forestove{calign primary angle})*\forest@ca@first@l}% \fi \fi \forest@calign@s@shift{-\forest@calign@anchor}% @@ -5225,64 +6754,123 @@ \forest@Pointanchor{\forest@ca@second@child}{child anchor}% \edef\forest@ca@second@child@anchor@s{\the\pgf@x}% \edef\forest@ca@second@child@anchor@l{\the\pgf@y}% - \pgfmathsetlengthmacro\forest@ca@desired@second@edge@s{tan(\forestove{calign secondary angle})*% - (\forest@ca@second@l-\forest@ca@second@child@anchor@l+\forest@ca@parent@anchor@l)}% - \pgfmathsetlengthmacro\forest@ca@desired@first@edge@s{tan(\forestove{calign primary angle})*% - (\forest@ca@first@l-\forest@ca@first@child@anchor@l+\forest@ca@parent@anchor@l)} - \pgfmathsetlengthmacro\forest@ca@desired@s@distance{\forest@ca@desired@second@edge@s-\forest@ca@desired@first@edge@s}% + \pgfmathtan@{\forestove{calign secondary angle}}% + \edef\forest@temp{\the\dimexpr + \forest@ca@second@l-\forest@ca@second@child@anchor@l+\forest@ca@parent@anchor@l}% + \pgfmathmultiply@{\pgfmathresult}{\expandafter\Pgf@geT\forest@temp}% + \edef\forest@ca@desired@second@edge@s{\the\dimexpr\pgfmathresult pt}% + %\pgfmathsetlengthmacro\forest@ca@desired@second@edge@s{% + % tan(\forestove{calign secondary angle})*% + % (\forest@ca@second@l-\forest@ca@second@child@anchor@l+\forest@ca@parent@anchor@l)}% + \pgfmathtan@{\forestove{calign primary angle}}% + \edef\forest@temp{\the\dimexpr + \forest@ca@first@l-\forest@ca@first@child@anchor@l+\forest@ca@parent@anchor@l}% + \pgfmathmultiply@{\pgfmathresult}{\expandafter\Pgf@geT\forest@temp}% + \edef\forest@ca@desired@first@edge@s{\the\dimexpr\pgfmathresult pt}% + %\pgfmathsetlengthmacro\forest@ca@desired@first@edge@s{% + % tan(\forestove{calign primary angle})*% + % (\forest@ca@first@l-\forest@ca@first@child@anchor@l+\forest@ca@parent@anchor@l)}% + \edef\forest@ca@desired@s@distance{\the\dimexpr + \forest@ca@desired@second@edge@s-\forest@ca@desired@first@edge@s}% + %\pgfmathsetlengthmacro\forest@ca@desired@s@distance{\forest@ca@desired@second@edge@s-\forest@ca@desired@first@edge@s}% \forestOget{\forest@ca@first@child}{s}\forest@ca@first@s \forestOget{\forest@ca@second@child}{s}\forest@ca@second@s - \pgfmathsetlengthmacro\forest@ca@actual@s@distance{% + \edef\forest@ca@actual@s@distance{\the\dimexpr \forest@ca@second@s+\forest@ca@second@child@anchor@s -\forest@ca@first@s-\forest@ca@first@child@anchor@s}% + %\pgfmathsetlengthmacro\forest@ca@actual@s@distance{% + % \forest@ca@second@s+\forest@ca@second@child@anchor@s + % -\forest@ca@first@s-\forest@ca@first@child@anchor@s}% \ifdim\forest@ca@desired@s@distance>\forest@ca@actual@s@distance\relax \ifdim\forest@ca@actual@s@distance=0pt \forestoget{n children}\forest@temp@n@children \forest@node@foreachchild{% \forest@pointanchor{child anchor}% \edef\forest@temp@child@anchor@s{\the\pgf@x}% - \pgfmathsetlengthmacro\forest@temp{% - \forest@ca@desired@first@edge@s+(\forestove{n}-1)*\forest@ca@desired@s@distance/(\forest@temp@n@children-1)+\forest@ca@first@child@anchor@s-\forest@temp@child@anchor@s}% - \forestolet{s}\forest@temp + \forestoeset{s}{\the\dimexpr + \forest@ca@desired@first@edge@s+\forest@ca@desired@s@distance*(\forestove{n}-1)/(\forest@temp@n@children-1)+\forest@ca@first@child@anchor@s-\forest@temp@child@anchor@s}% + %\pgfmathsetlengthmacro\forest@temp{% + % \forest@ca@desired@first@edge@s+(\forestove{n}-1)*\forest@ca@desired@s@distance/(\forest@temp@n@children-1)+\forest@ca@first@child@anchor@s-\forest@temp@child@anchor@s}% + %\forestolet{s}\forest@temp }% \def\forest@calign@anchor{0pt}% \else - \pgfmathsetmacro\forest@ca@ratio{% - \forest@ca@desired@s@distance/\forest@ca@actual@s@distance}% + \edef\forest@marshal{\noexpand\pgfmathdivide@ + {\expandafter\Pgf@geT\forest@ca@desired@s@distance}% + {\expandafter\Pgf@geT\forest@ca@actual@s@distance}% + }\forest@marshal + \let\forest@ca@ratio\pgfmathresult + %\pgfmathsetmacro\forest@ca@ratio{% + % \forest@ca@desired@s@distance/\forest@ca@actual@s@distance}% \forest@node@foreachchild{% \forest@pointanchor{child anchor}% \edef\forest@temp@child@anchor@s{\the\pgf@x}% - \pgfmathsetlengthmacro\forest@temp{% - \forest@ca@ratio*(% - \forestove{s}-\forest@ca@first@s - +\forest@temp@child@anchor@s-\forest@ca@first@child@anchor@s)% - +\forest@ca@first@s + \edef\forest@marshal{\noexpand\pgfmathmultiply@ + {\forest@ca@ratio}% + {\expandafter\Pgf@geT\the\dimexpr + \forestove{s}-\forest@ca@first@s+% + \forest@temp@child@anchor@s-\forest@ca@first@child@anchor@s}% + }\forest@marshal + \forestoeset{s}{\the\dimexpr\pgfmathresult pt+\forest@ca@first@s +\forest@ca@first@child@anchor@s-\forest@temp@child@anchor@s}% - \forestolet{s}\forest@temp - }% - \pgfmathsetlengthmacro\forest@calign@anchor{% - -tan(\forestove{calign primary angle})*(\forest@ca@first@l-\forest@ca@first@child@anchor@l+\forest@ca@parent@anchor@l)% - +\forest@ca@first@child@anchor@s-\forest@ca@parent@anchor@s + % \pgfmathsetlengthmacro\forest@temp{% + % \forest@ca@ratio*(% + % \forestove{s}-\forest@ca@first@s + % +\forest@temp@child@anchor@s-\forest@ca@first@child@anchor@s)% + % +\forest@ca@first@s + % +\forest@ca@first@child@anchor@s-\forest@temp@child@anchor@s}% + % \forestolet{s}\forest@temp }% + \pgfmathtan@{\forestove{calign primary angle}}% + \edef\forest@marshal{\noexpand\pgfmathmultiply@ + {\pgfmathresult}% + {\expandafter\Pgf@geT\the\dimexpr + \forest@ca@first@l-\forest@ca@first@child@anchor@l+\forest@ca@parent@anchor@l}% + }\forest@marshal + \edef\forest@calign@anchor{\the\dimexpr + -\pgfmathresult pt+\forest@ca@first@child@anchor@s-\forest@ca@parent@anchor@s}% + % \pgfmathsetlengthmacro\forest@calign@anchor{% + % -tan(\forestove{calign primary angle})*(\forest@ca@first@l-\forest@ca@first@child@anchor@l+\forest@ca@parent@anchor@l)% + % +\forest@ca@first@child@anchor@s-\forest@ca@parent@anchor@s + % }% \fi \else \ifdim\forest@ca@desired@s@distance<\forest@ca@actual@s@distance\relax - \pgfmathsetlengthmacro\forest@ca@ratio{% - \forest@ca@actual@s@distance/\forest@ca@desired@s@distance}% + \edef\forest@marshal{\noexpand\pgfmathdivide@ + {\expandafter\Pgf@geT\forest@ca@actual@s@distance}% + {\expandafter\Pgf@geT\forest@ca@desired@s@distance}% + }\forest@marshal + \let\forest@ca@ratio\pgfmathresult + %\pgfmathsetlengthmacro\forest@ca@ratio{% + % \forest@ca@actual@s@distance/\forest@ca@desired@s@distance}% \forest@node@foreachchild{% \forest@pointanchor{child anchor}% \edef\forest@temp@child@anchor@l{\the\pgf@y}% - \pgfmathsetlengthmacro\forest@temp{% - \forest@ca@ratio*(% - \forestove{l}+\forest@ca@parent@anchor@l-\forest@temp@child@anchor@l) - -\forest@ca@parent@anchor@l+\forest@temp@child@anchor@l}% - \forestolet{l}\forest@temp + \edef\forest@marshal{\noexpand\pgfmathmultiply@ + {\forest@ca@ratio}% + {\expandafter\Pgf@geT\the\dimexpr\forestove{l}+\forest@ca@parent@anchor@l-\forest@temp@child@anchor@l}% + }\forest@marshal + \forestoeset{l}{\the\dimexpr + \pgfmathresult pt-\forest@ca@parent@anchor@l+\forest@temp@child@anchor@l}% + % \pgfmathsetlengthmacro\forest@temp{% + % \forest@ca@ratio*(% + % \forestove{l}+\forest@ca@parent@anchor@l-\forest@temp@child@anchor@l) + % -\forest@ca@parent@anchor@l+\forest@temp@child@anchor@l}% + % \forestolet{l}\forest@temp }% \forestOget{\forest@ca@first@child}{l}\forest@ca@first@l - \pgfmathsetlengthmacro\forest@calign@anchor{% - -tan(\forestove{calign primary angle})*(\forest@ca@first@l+\forest@ca@parent@anchor@l-\forest@temp@child@anchor@l)% - +\forest@ca@first@child@anchor@s-\forest@ca@parent@anchor@s - }% + \pgfmathtan@{\forestove{calign primary angle}}% + \edef\forest@marshal{\noexpand\pgfmathmultiply@ + {\pgfmathresult}% + {\expandafter\Pgf@geT\the\dimexpr + \forest@ca@first@l+\forest@ca@parent@anchor@l-\forest@temp@child@anchor@l}% + }\forest@marshal + \edef\forest@calign@anchor{\the\dimexpr + -\pgfmathresult pt+\forest@ca@first@child@anchor@s-\forest@ca@parent@anchor@s}% + % \pgfmathsetlengthmacro\forest@calign@anchor{% + % -tan(\forestove{calign primary angle})*(\forest@ca@first@l+\forest@ca@parent@anchor@l-\forest@temp@child@anchor@l)% + % +\forest@ca@first@child@anchor@s-\forest@ca@parent@anchor@s + % }% \fi \fi \forest@calign@s@shift{-\forest@calign@anchor}% @@ -5323,7 +6911,7 @@ \eappto\forest@node@edge{\noexpand\pgfsyssoftpath@movetotoken{\forest@getedge@pa@l}{\forest@getedge@pa@s}}% \pgfgettransform\forest@temp@transform \pgftransformreset - \pgftransformrotate{\forestove{grow}}% + \forest@pgfqtransformrotate{\forestove{grow}}% \def\forest@all@edges{}% \forest@node@foreachchild{% \forestoget{#1@edge@#2}\forest@temp@edge @@ -5897,8 +7485,12 @@ }\forest@marshal } \def\forest@node@computeabsolutepositions@#1#2#3{% - \pgfpointadd{\pgfpoint{#1}{#2}}{% - \pgfpointadd{\pgfpolar{#3}{\forestove{l}}}{\pgfpolar{90 + #3}{\forestove{s}}}}% + \pgfpointadd + {\pgfqpoint{#1}{#2}}% + {\pgfpointadd + {\pgfqpointpolar{#3}{\forestove{l}}}% + {\pgfqpointpolar{\numexpr 90+#3\relax}{\forestove{s}}}% + }% \pgfgetlastxy\forest@temp@x\forest@temp@y \forestolet{x}\forest@temp@x \forestolet{y}\forest@temp@y @@ -6052,7 +7644,7 @@ \newdimen\forest@ys \def\forest@setupgrowline#1{% \edef\forest@grow{#1}% - \pgfpointpolar\forest@grow{1pt}% + \pgfqpointpolar{\forest@grow}{1pt}% \forest@xg=\pgf@x \forest@yg=\pgf@y \forest@xs=-\pgf@y @@ -6245,6 +7837,7 @@ \let\forest@previous@px\forest@px \let\forest@previous@py\forest@py } +\patchcmd{\pgfpointintersectionoflines}{\pgfpoint}{\pgfqpoint}{}{} \def\forest@getnegativetightedgeofpath#1#2{% \forest@get@onetightedgeofpath#1\forest@sort@ascending#2} \def\forest@getpositivetightedgeofpath#1#2{% @@ -6458,7 +8051,11 @@ \pgf@x=0pt \fi \fi - \csname pgfmathatan2\endcsname{\pgf@x}{\pgf@y}% + \edef\forest@marshal{% + \noexpand\pgfmathatantwo@ + {\expandafter\Pgf@geT\the\pgf@x}% + {\expandafter\Pgf@geT\the\pgf@y}% + }\forest@marshal \let\forest@current@atan\pgfmathresult \ifx\forest@last@atan\relax \def\forest@last@x{#1}% @@ -6501,7 +8098,7 @@ }% {% \pgftransformreset - \pgftransformrotate{\forest@grow}% + \forest@pgfqtransformrotate{\forest@grow}% \forest@pgfpathtransformed\forest@gre@path }% \pgfsyssoftpath@getcurrentpath#2% @@ -6514,7 +8111,7 @@ }% {% \pgftransformreset - \pgftransformrotate{\forest@grow}% + \forest@pgfqtransformrotate{\forest@grow}% \forest@pgfpathtransformed\forest@gre@path }% \pgfsyssoftpath@getcurrentpath#2% @@ -6531,13 +8128,13 @@ }% {% \pgftransformreset - \pgftransformrotate{\forest@grow}% + \forest@pgfqtransformrotate{\forest@grow}% \forest@pgfpathtransformed\forest@gre@negpath }% \pgfsyssoftpath@getcurrentpath#2% {% \pgftransformreset - \pgftransformrotate{\forest@grow}% + \forest@pgfqtransformrotate{\forest@grow}% \forest@pgfpathtransformed\forest@gre@pospath }% \pgfsyssoftpath@getcurrentpath#3% @@ -6751,7 +8348,7 @@ \def\forest@path@getboundingrectangle@ls#1#2{% {% \pgftransformreset - \pgftransformrotate{-(#2)}% + \forest@pgfqtransformrotate{-#2}% \forest@pgfpathtransformed#1% }% \pgfsyssoftpath@getcurrentpath\forest@gbr@rotatedpath @@ -6775,6 +8372,17 @@ \ifdim#2<\pgf@ya\relax\pgf@ya=#2 \fi \ifdim#2>\pgf@yb\relax\pgf@yb=#2 \fi } +\let\forest@pgfqtransformrotate\pgftransformrotate +\let\forest@pgftransformcm\pgftransformcm +\let\forest@pgf@transformcm\pgf@transformcm +\patchcmd{\forest@pgfqtransformrotate}{\pgfmathparse{#1}}{\edef\pgfmathresult{\number\numexpr#1}}{}{} +\patchcmd{\forest@pgfqtransformrotate}{\pgftransformcm}{\forest@pgftransformcm}{}{} +\patchcmd{\forest@pgftransformcm}{\pgf@transformcm}{\forest@pgf@transformcm}{}{} +\patchcmd{\forest@pgf@transformcm}{\pgfmathsetlength}{\forest@pgf@transformcm@setlength}{}{} % 4x +\patchcmd{\forest@pgf@transformcm}{\pgfmathsetlength}{\forest@pgf@transformcm@setlength}{}{} % 4x +\patchcmd{\forest@pgf@transformcm}{\pgfmathsetlength}{\forest@pgf@transformcm@setlength}{}{} % 4x +\patchcmd{\forest@pgf@transformcm}{\pgfmathsetlength}{\forest@pgf@transformcm@setlength}{}{} % 4x +\def\forest@pgf@transformcm@setlength#1#2{#1=#2pt} \pgfkeys{/forest/external/.cd, %copy command/.initial={cp "\source" "\target"}, copy command/.initial={}, @@ -6796,10 +8404,11 @@ }% }{}% } +\newread\forest@copy@in +\newwrite\forest@copy@out \def\forest@file@copy@#1#2{% - \newread\forest@copy@in + \begingroup \openin\forest@copy@in=#1 - \newwrite\forest@copy@out \immediate\openout\forest@copy@out#2 \endlinechar-1 \loop @@ -6809,6 +8418,7 @@ \repeat \immediate\closeout\forest@copy@out \closein\forest@copy@in + \endgroup } \newif\ifforest@external@optimize@ \forest@external@optimize@true @@ -6869,11 +8479,15 @@ \forest@next{#3}% } \def\forest@config#1{% - \def\forest@stages{stages}% + \forest@defstages{stages}% \forestset{@config/.cd,#1}% } +\def\forest@defstages#1{% + \def\forest@stages{#1}% +} \forestset{@config/.cd, - stages/.store in=\forest@stages, + %stages/.store in=\forest@stages, + stages/.code={\forest@defstages{#1}}, .unknown/.code={\PackageError{forest}{Unknown config option for forest environment/command.}{In Forest v2.0.0 and v2.0.1, this (parenthesized) argument accepted the definition of style stages for the current forest environment/macro. Since v2.0.2, you should write "\string\begin{forest}(stages={...})...\string\end{forest}", or "\string\Forest(stages={...}){...}" instead.}} } \def\forest@group@env#1{{\forest@env{#1}}} @@ -7094,9 +8708,9 @@ \pgfkeysvalueof{/pgf/inner xsep},\pgfkeysvalueof{/pgf/outer xsep}% } { - l sep={\the\ht\strutbox+\pgfkeysvalueof{/pgf/inner ysep}}, + l sep'/.expanded={\the\dimexpr\the\ht\strutbox+\pgfkeysvalueof{/pgf/inner ysep}}, l={l_sep()+abs(max_y()-min_y())+2*\pgfkeysvalueof{/pgf/outer ysep}}, - s sep={2*\pgfkeysvalueof{/pgf/inner xsep}} + s sep'/.expanded={\the\dimexpr \pgfkeysvalueof{/pgf/inner xsep}*2} } {l sep,l,s sep} \pgfqkeys{/forest/@cs}{% @@ -7111,11 +8725,11 @@ \forest@forestcs@resetxy}, anchor/.code={\forest@forestcs@anchor{#1}}, l/.code={% - \pgfmathsetlengthmacro\forest@forestcs@l{#1}% + \forestmathsetlengthmacro\forest@forestcs@l{#1}% \forest@forestcs@ls }, s/.code={% - \pgfmathsetlengthmacro\forest@forestcs@s{#1}% + \forestmathsetlengthmacro\forest@forestcs@s{#1}% \forest@forestcs@ls }, .unknown/.code={% @@ -7130,16 +8744,16 @@ } \def\forest@forestcs@resetxy{% \ifnum\forest@cn=0 \forest@cs@invalidnodeerror\fi - \global\pgf@x\forestove{x}% - \global\pgf@y\forestove{y}% + \global\pgf@x\forestove{x}\relax + \global\pgf@y\forestove{y}\relax } \def\forest@forestcs@ls{% \ifdefined\forest@forestcs@l \ifdefined\forest@forestcs@s {% \pgftransformreset - \pgftransformrotate{\forestove{grow}}% - \pgfpointtransformed{\pgfpoint{\forest@forestcs@l}{\forest@forestcs@s}}% + \forest@pgfqtransformrotate{\forestove{grow}}% + \pgfpointtransformed{\pgfqpoint{\forest@forestcs@l}{\forest@forestcs@s}}% }% \global\advance\pgf@x\forestove{x}% \global\advance\pgf@y\forestove{y}% @@ -7233,10 +8847,18 @@ \forest@anchor@forwardtotikztrue \forest@anchor@do{#1}{children}{\forest@referencednodeid}% } +\pgfdeclaregenericanchor{-children}{% + \forest@anchor@forwardtotikztrue + \forest@anchor@do{#1}{-children}{\forest@referencednodeid}% +} \pgfdeclaregenericanchor{children first}{% \forest@anchor@forwardtotikztrue \forest@anchor@do{#1}{children first}{\forest@referencednodeid}% } +\pgfdeclaregenericanchor{-children first}{% + \forest@anchor@forwardtotikztrue + \forest@anchor@do{#1}{-children first}{\forest@referencednodeid}% +} \pgfdeclaregenericanchor{first}{% \forest@anchor@forwardtotikztrue \forest@anchor@do{#1}{first}{\forest@referencednodeid}% @@ -7245,14 +8867,26 @@ \forest@anchor@forwardtotikztrue \forest@anchor@do{#1}{parent first}{\forest@referencednodeid}% } +\pgfdeclaregenericanchor{-parent first}{% + \forest@anchor@forwardtotikztrue + \forest@anchor@do{#1}{-parent first}{\forest@referencednodeid}% +} \pgfdeclaregenericanchor{parent}{% \forest@anchor@forwardtotikztrue \forest@anchor@do{#1}{parent}{\forest@referencednodeid}% } +\pgfdeclaregenericanchor{-parent}{% + \forest@anchor@forwardtotikztrue + \forest@anchor@do{#1}{-parent}{\forest@referencednodeid}% +} \pgfdeclaregenericanchor{parent last}{% \forest@anchor@forwardtotikztrue \forest@anchor@do{#1}{parent last}{\forest@referencednodeid}% } +\pgfdeclaregenericanchor{-parent last}{% + \forest@anchor@forwardtotikztrue + \forest@anchor@do{#1}{-parent last}{\forest@referencednodeid}% +} \pgfdeclaregenericanchor{last}{% \forest@anchor@forwardtotikztrue \forest@anchor@do{#1}{last}{\forest@referencednodeid}% @@ -7261,14 +8895,26 @@ \forest@anchor@forwardtotikztrue \forest@anchor@do{#1}{children last}{\forest@referencednodeid}% } +\pgfdeclaregenericanchor{-children last}{% + \forest@anchor@forwardtotikztrue + \forest@anchor@do{#1}{-children last}{\forest@referencednodeid}% +} \pgfdeclaregenericanchor{children'}{% \forest@anchor@forwardtotikztrue \forest@anchor@do{#1}{children'}{\forest@referencednodeid}% } +\pgfdeclaregenericanchor{-children'}{% + \forest@anchor@forwardtotikztrue + \forest@anchor@do{#1}{-children'}{\forest@referencednodeid}% +} \pgfdeclaregenericanchor{children first'}{% \forest@anchor@forwardtotikztrue \forest@anchor@do{#1}{children first'}{\forest@referencednodeid}% } +\pgfdeclaregenericanchor{-children first'}{% + \forest@anchor@forwardtotikztrue + \forest@anchor@do{#1}{-children first'}{\forest@referencednodeid}% +} \pgfdeclaregenericanchor{first'}{% \forest@anchor@forwardtotikztrue \forest@anchor@do{#1}{first'}{\forest@referencednodeid}% @@ -7277,14 +8923,26 @@ \forest@anchor@forwardtotikztrue \forest@anchor@do{#1}{parent first'}{\forest@referencednodeid}% } +\pgfdeclaregenericanchor{-parent first'}{% + \forest@anchor@forwardtotikztrue + \forest@anchor@do{#1}{-parent first'}{\forest@referencednodeid}% +} \pgfdeclaregenericanchor{parent'}{% \forest@anchor@forwardtotikztrue \forest@anchor@do{#1}{parent'}{\forest@referencednodeid}% } +\pgfdeclaregenericanchor{-parent'}{% + \forest@anchor@forwardtotikztrue + \forest@anchor@do{#1}{-parent'}{\forest@referencednodeid}% +} \pgfdeclaregenericanchor{parent last'}{% \forest@anchor@forwardtotikztrue \forest@anchor@do{#1}{parent last'}{\forest@referencednodeid}% } +\pgfdeclaregenericanchor{-parent last'}{% + \forest@anchor@forwardtotikztrue + \forest@anchor@do{#1}{-parent last'}{\forest@referencednodeid}% +} \pgfdeclaregenericanchor{last'}{% \forest@anchor@forwardtotikztrue \forest@anchor@do{#1}{last'}{\forest@referencednodeid}% @@ -7293,6 +8951,10 @@ \forest@anchor@forwardtotikztrue \forest@anchor@do{#1}{children last'}{\forest@referencednodeid}% } +\pgfdeclaregenericanchor{-children last'}{% + \forest@anchor@forwardtotikztrue + \forest@anchor@do{#1}{-children last'}{\forest@referencednodeid}% +} \def\forest@anchor@do#1#2#3{% #1 = shape name, #2 = (potentially) forest anchor, #3 = node id \forest@fornode{#3}{% \def\forest@temp@anchor{#2}% @@ -7322,9 +8984,19 @@ \forest@anchor@isbordertrue \edef\forest@temp@anchor{\number\numexpr\forestove{grow}-\forestove{rotate}}% } +\csdef{forest@anchor@@-children'}{% + \forest@anchor@isbordertrue + \edef\forest@temp@anchor{\number\numexpr 180+\forestove{grow}-\forestove{rotate}}% +} \csdef{forest@anchor@@parent'}{% \forest@anchor@isbordertrue - \edef\forest@temp@anchor{\number\numexpr\forestove{grow}-\forestove{rotate}+180}% + \edef\forest@temp@grow{\ifnum\forestove{@parent}=0 \forestove{grow}\else\forestOve{\forestove{@parent}}{grow}\fi}% + \edef\forest@temp@anchor{\number\numexpr\forest@temp@grow-\forestove{rotate}+180}% +} +\csdef{forest@anchor@@-parent'}{% + \forest@anchor@isbordertrue + \edef\forest@temp@grow{\ifnum\forestove{@parent}=0 \forestove{grow}\else\forestOve{\forestove{@parent}}{grow}\fi}% + \edef\forest@temp@anchor{\number\numexpr\forest@temp@grow-\forestove{rotate}}% } \csdef{forest@anchor@@first'}{% \forest@anchor@isbordertrue @@ -7336,14 +9008,34 @@ } \csdef{forest@anchor@@parent first'}{% \forest@anchor@isbordertrue - \edef\forest@temp@anchor@parent{\number\numexpr\forestove{grow}-\forestove{rotate}+180}% - \edef\forest@temp@anchor@first{\number\numexpr\forestove{grow}-\forestove{rotate}\ifnum\forestove{reversed}=0 -\else+\fi90}% + \edef\forest@temp@grow{\ifnum\forestove{@parent}=0 \forestove{grow}\else\forestOve{\forestove{@parent}}{grow}\fi}% + \edef\forest@temp@reversed{\ifnum\forestove{@parent}=0 \forestove{reversed}\else\forestOve{\forestove{@parent}}{reversed}\fi}% + \edef\forest@temp@anchor@parent{\number\numexpr\forest@temp@grow-\forestove{rotate}+180}% + \edef\forest@temp@anchor@first{\number\numexpr\forest@temp@grow-\forestove{rotate}\ifnum\forest@temp@reversed=0 -\else+\fi90}% + \forest@getaverageangle{\forest@temp@anchor@parent}{\forest@temp@anchor@first}\forest@temp@anchor +} +\csdef{forest@anchor@@-parent first'}{% + \forest@anchor@isbordertrue + \edef\forest@temp@grow{\ifnum\forestove{@parent}=0 \forestove{grow}\else\forestOve{\forestove{@parent}}{grow}\fi}% + \edef\forest@temp@reversed{\ifnum\forestove{@parent}=0 \forestove{reversed}\else\forestOve{\forestove{@parent}}{reversed}\fi}% + \edef\forest@temp@anchor@parent{\number\numexpr\forest@temp@grow-\forestove{rotate}}% + \edef\forest@temp@anchor@first{\number\numexpr\forest@temp@grow-\forestove{rotate}\ifnum\forest@temp@reversed=0 -\else+\fi90}% \forest@getaverageangle{\forest@temp@anchor@parent}{\forest@temp@anchor@first}\forest@temp@anchor } \csdef{forest@anchor@@parent last'}{% \forest@anchor@isbordertrue - \edef\forest@temp@anchor@parent{\number\numexpr\forestove{grow}-\forestove{rotate}+180}% - \edef\forest@temp@anchor@last{\number\numexpr\forestove{grow}-\forestove{rotate}\ifnum\forestove{reversed}=0 +\else-\fi90}% + \edef\forest@temp@grow{\ifnum\forestove{@parent}=0 \forestove{grow}\else\forestOve{\forestove{@parent}}{grow}\fi}% + \edef\forest@temp@reversed{\ifnum\forestove{@parent}=0 \forestove{reversed}\else\forestOve{\forestove{@parent}}{reversed}\fi}% + \edef\forest@temp@anchor@parent{\number\numexpr\forest@temp@grow-\forestove{rotate}+180}% + \edef\forest@temp@anchor@last{\number\numexpr\forest@temp@grow-\forestove{rotate}\ifnum\forest@temp@reversed=0 +\else-\fi90}% + \forest@getaverageangle{\forest@temp@anchor@parent}{\forest@temp@anchor@last}\forest@temp@anchor +} +\csdef{forest@anchor@@-parent last'}{% + \forest@anchor@isbordertrue + \edef\forest@temp@grow{\ifnum\forestove{@parent}=0 \forestove{grow}\else\forestOve{\forestove{@parent}}{grow}\fi}% + \edef\forest@temp@reversed{\ifnum\forestove{@parent}=0 \forestove{reversed}\else\forestOve{\forestove{@parent}}{reversed}\fi}% + \edef\forest@temp@anchor@parent{\number\numexpr\forest@temp@grow-\forestove{rotate}}% + \edef\forest@temp@anchor@last{\number\numexpr\forest@temp@grow-\forestove{rotate}\ifnum\forest@temp@reversed=0 +\else-\fi90}% \forest@getaverageangle{\forest@temp@anchor@parent}{\forest@temp@anchor@last}\forest@temp@anchor } \csdef{forest@anchor@@children first'}{% @@ -7351,19 +9043,37 @@ \edef\forest@temp@anchor@first{\number\numexpr\forestove{grow}-\forestove{rotate}\ifnum\forestove{reversed}=0 -\else+\fi90}% \forest@getaverageangle{\forestove{grow}-\forestove{rotate}}{\forest@temp@anchor@first}\forest@temp@anchor } +\csdef{forest@anchor@@-children first'}{% + \forest@anchor@isbordertrue + \edef\forest@temp@anchor@first{\number\numexpr\forestove{grow}-\forestove{rotate}\ifnum\forestove{reversed}=0 -\else+\fi90}% + \forest@getaverageangle{180+\forestove{grow}-\forestove{rotate}}{\forest@temp@anchor@first}\forest@temp@anchor +} \csdef{forest@anchor@@children last'}{% \forest@anchor@isbordertrue \edef\forest@temp@anchor@last{\number\numexpr\forestove{grow}-\forestove{rotate}\ifnum\forestove{reversed}=0 +\else-\fi90}% \forest@getaverageangle{\forestove{grow}-\forestove{rotate}}{\forest@temp@anchor@last}\forest@temp@anchor } +\csdef{forest@anchor@@-children last'}{% + \forest@anchor@isbordertrue + \edef\forest@temp@anchor@last{\number\numexpr\forestove{grow}-\forestove{rotate}\ifnum\forestove{reversed}=0 +\else-\fi90}% + \forest@getaverageangle{180+\forestove{grow}-\forestove{rotate}}{\forest@temp@anchor@last}\forest@temp@anchor +} \csdef{forest@anchor@@children}{% \forest@anchor@snapbordertocompasstrue \csuse{forest@anchor@@children'}% } +\csdef{forest@anchor@@-children}{% + \forest@anchor@snapbordertocompasstrue + \csuse{forest@anchor@@-children'}% +} \csdef{forest@anchor@@parent}{% \forest@anchor@snapbordertocompasstrue \csuse{forest@anchor@@parent'}% } +\csdef{forest@anchor@@-parent}{% + \forest@anchor@snapbordertocompasstrue + \csuse{forest@anchor@@-parent'}% +} \csdef{forest@anchor@@first}{% \forest@anchor@snapbordertocompasstrue \csuse{forest@anchor@@first'}% @@ -7376,41 +9086,67 @@ \forest@anchor@snapbordertocompasstrue \csuse{forest@anchor@@parent first'}% } +\csdef{forest@anchor@@-parent first}{% + \forest@anchor@snapbordertocompasstrue + \csuse{forest@anchor@@-parent first'}% +} \csdef{forest@anchor@@parent last}{% \forest@anchor@snapbordertocompasstrue \csuse{forest@anchor@@parent last'}% } +\csdef{forest@anchor@@-parent last}{% + \forest@anchor@snapbordertocompasstrue + \csuse{forest@anchor@@-parent last'}% +} \csdef{forest@anchor@@children first}{% \forest@anchor@snapbordertocompasstrue \csuse{forest@anchor@@children first'}% } +\csdef{forest@anchor@@-children first}{% + \forest@anchor@snapbordertocompasstrue + \csuse{forest@anchor@@-children first'}% +} \csdef{forest@anchor@@children last}{% \forest@anchor@snapbordertocompasstrue \csuse{forest@anchor@@children last'}% } +\csdef{forest@anchor@@-children last}{% + \forest@anchor@snapbordertocompasstrue + \csuse{forest@anchor@@-children last'}% +} \def\forest@getaverageangle#1#2#3{% \edef\forest@temp{\number\numexpr #1-#2+540}% - \pgfmathMod{\forest@temp}{360}\pgfmathtruncatemacro\pgfmathresult{\pgfmathresult} - \edef\forest@temp{360+#2+((\pgfmathresult-180)/2)}% - \pgfmathMod{\forest@temp}{360}\pgfmathtruncatemacro#3{\pgfmathresult}% -} + \expandafter\pgfmathMod@\expandafter{\forest@temp}{360}% + \forest@truncatepgfmathresult + \edef\forest@temp{\number\numexpr 360+#2+((\pgfmathresult-180)/2)}% + \expandafter\pgfmathMod@\expandafter{\forest@temp}{360}% + \forest@truncatepgfmathresult + \let#3\pgfmathresult +} +\def\forest@truncatepgfmathresult{% + \afterassignment\forest@gobbletoEND + \forest@temp@count=\pgfmathresult\forest@END + \def\pgfmathresult{\the\forest@temp@count}% +} +\def\forest@gobbletoEND#1\forest@END{} \def\forest@anchor@border@to@compass{% - \ifforest@anchor@isborder + \ifforest@anchor@isborder % snap to 45 deg, to range 0-360 \ifforest@anchor@snapbordertocompass \forest@anchor@snap@border@to@compass - \else - \pgfmathMod{\forest@temp@anchor}{360}% - \pgfmathtruncatemacro\forest@temp@anchor{\pgfmathresult}% + \else % to range 0-360 + \pgfmathMod@{\forest@temp@anchor}{360}% + \forest@truncatepgfmathresult + \let\forest@temp@anchor\pgfmathresult \fi - \ifforest@anchor@forwardtotikz - \ifcsname pgf@anchor% - @\csname pgf@sh@ns@\pgfreferencednodename\endcsname - @\csname forest@compass@\forest@temp@anchor\endcsname - \endcsname - \letcs\forest@temp@anchor{forest@compass@\forest@temp@anchor}% - \fi - \else - \ifforest@anchor@snapbordertocompass + \ifforest@anchor@snapbordertocompass + \ifforest@anchor@forwardtotikz + \ifcsname pgf@anchor% + @\csname pgf@sh@ns@\pgfreferencednodename\endcsname + @\csname forest@compass@\forest@temp@anchor\endcsname + \endcsname + \letcs\forest@temp@anchor{forest@compass@\forest@temp@anchor}% + \fi + \else \letcs\forest@temp@anchor{forest@compass@\forest@temp@anchor}% \fi \fi @@ -7426,11 +9162,12 @@ \csdef{forest@compass@315}{south east} \csdef{forest@compass@360}{east} \def\forest@anchor@snap@border@to@compass{% - \pgfmathMod{\forest@temp@anchor}{360}% - \pgfmathdivide{\pgfmathresult}{45}% - \pgfmathround{\pgfmathresult}% - \pgfmathmultiply{\pgfmathresult}{45}% - \pgfmathtruncatemacro\forest@temp@anchor{\pgfmathresult}% + \pgfmathMod@{\forest@temp@anchor}{360}% + \pgfmathdivide@{\pgfmathresult}{45}% + \pgfmathround@{\pgfmathresult}% + \pgfmathmultiply@{\pgfmathresult}{45}% + \forest@truncatepgfmathresult + \let\forest@temp@anchor\pgfmathresult } \def\forest@anchor@forward#1{% #1 = shape name \ifdefempty\forest@temp@anchor{% @@ -7452,34 +9189,32 @@ \if\relax#2\relax#1\fi } \expandafter\def\expandafter\forest@referencednodename@stripafter\expandafter#\expandafter1\forest@pgf@notyetpositioned\relax{#1} +\def\forest@pointanchor#1{% #1 = anchor + \forest@Pointanchor{\forest@cn}{#1}% +} \def\forest@Pointanchor#1#2{% #1 = node id, #2 = anchor - {% - \def\forest@pa@temp@name{name}% - \forestOifdefined{#1}{@box}{% - \forestOget{#1}{@box}\forest@temp - \ifdefempty\forest@temp{}{% - \def\forest@pa@temp@name{later@name}% - }% - }{}% - \setbox0\hbox{% - \begin{pgfpicture}% - \if\relax\forestOve{#1}{#2}\relax - \pgfpointanchor{\forestOve{#1}{\forest@pa@temp@name}}{center}% - \else - \pgfpointanchor{\forestOve{#1}{\forest@pa@temp@name}}{\forestOve{#1}{#2}}% - \fi - \xdef\forest@global@marshal{% - \noexpand\global\noexpand\pgf@x=\the\pgf@x\relax - \noexpand\global\noexpand\pgf@y=\the\pgf@y - }% - \end{pgfpicture}% + \def\forest@pa@temp@name{name}% + \forestOifdefined{#1}{@box}{% + \forestOget{#1}{@box}\forest@temp + \ifdefempty\forest@temp{}{% + \def\forest@pa@temp@name{later@name}% }% + }{}% + \setbox0\hbox{% + \begin{pgfpicture}% this is expensive: so that's why caching + \if\relax\forestOve{#1}{#2}\relax + \pgfpointanchor{\forestOve{#1}{\forest@pa@temp@name}}{center}% + \else + \pgfpointanchor{\forestOve{#1}{\forest@pa@temp@name}}{\forestOve{#1}{#2}}% + \fi + \xdef\forest@global@marshal{% + \noexpand\global\noexpand\pgf@x=\the\pgf@x\relax + \noexpand\global\noexpand\pgf@y=\the\pgf@y\relax\relax + }% + \end{pgfpicture}% }% \forest@global@marshal } -\def\forest@pointanchor#1{% #1 = anchor - \forest@Pointanchor{\forest@cn}{#1}% -} \ifdefempty{\forest@compat}{}{% \RequirePackage{forest-compat} } |