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 | |
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')
-rw-r--r-- | Master/texmf-dist/doc/latex/forest/README | 2 | ||||
-rw-r--r-- | Master/texmf-dist/doc/latex/forest/forest-doc.pdf | bin | 1151255 -> 1183175 bytes | |||
-rw-r--r-- | Master/texmf-dist/doc/latex/forest/forest-doc.tex | 2342 | ||||
-rw-r--r-- | Master/texmf-dist/doc/latex/forest/forest.pdf | bin | 440369 -> 496572 bytes | |||
-rw-r--r-- | Master/texmf-dist/source/latex/forest/forest-index.dtx | 208 | ||||
-rw-r--r-- | Master/texmf-dist/source/latex/forest/forest-libs.dtx | 56 | ||||
-rw-r--r-- | Master/texmf-dist/source/latex/forest/forest.dtx | 3109 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/forest/forest-compat.sty | 89 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/forest/forest-doc.sty | 8 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/forest/forest-index.sty | 158 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/forest/forest-lib-edges.sty | 21 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/forest/forest-lib-linguistics.sty | 2 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/forest/forest.sty | 2839 |
13 files changed, 6950 insertions, 1884 deletions
diff --git a/Master/texmf-dist/doc/latex/forest/README b/Master/texmf-dist/doc/latex/forest/README index a5d342c8767..36e0e0f0e76 100644 --- a/Master/texmf-dist/doc/latex/forest/README +++ b/Master/texmf-dist/doc/latex/forest/README @@ -1,4 +1,4 @@ -LaTeX package: forest [2016/04/09 v2.0.3 Drawing (linguistic) trees] +LaTeX package: forest [2016/12/05 v2.1 Drawing (linguistic) trees] Copyright (c) 2016 Saso Zivanovic (Sa\v{s}o \v{Z}ivanovi\'{c}) diff --git a/Master/texmf-dist/doc/latex/forest/forest-doc.pdf b/Master/texmf-dist/doc/latex/forest/forest-doc.pdf Binary files differindex 69bc4ac2d1e..28e68d4bcf5 100644 --- a/Master/texmf-dist/doc/latex/forest/forest-doc.pdf +++ b/Master/texmf-dist/doc/latex/forest/forest-doc.pdf diff --git a/Master/texmf-dist/doc/latex/forest/forest-doc.tex b/Master/texmf-dist/doc/latex/forest/forest-doc.tex index d1073acdabc..a7354685334 100644 --- a/Master/texmf-dist/doc/latex/forest/forest-doc.tex +++ b/Master/texmf-dist/doc/latex/forest/forest-doc.tex @@ -1,7 +1,7 @@ %% forest-doc.tex %% `forest-doc.tex` is a main documentation source 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 %% @@ -29,7 +29,7 @@ nohead ]{geometry} -%\immediate\write18{makeindex -s forest-doc.ist forest-doc} +\immediate\write18{makeindex -s forest-doc.ist forest-doc} \def\indexlettertotoc#1\relax{% \phantomsection\addcontentsline{toc}{subsection}{#1}% #1% @@ -55,6 +55,23 @@ } \usepackage{forest-doc} +% \usepackage{patchpgf} +% \newcommand\pgfprofilenewforcommandcs[2]{% +% \expandafter\pgfprofilenewforcommand\expandafter{\csname #1\endcsname}{#2}} +% \newcommand\pgfprofilenewforpgfkey[1]{% +% \edef\marshal{% +% \noexpand\pgfprofilenewforcommandpattern[#1]{\expandonce{\csname pgfk@#1/.@cmd\endcsname}}{####1\noexpand\pgfeov}{####1\noexpand\pgfeov} +% }\marshal +% } +% \usetikzlibrary{profiler} +% \makeatletter +% \pgfprofilenewforcommand{\forestindex@index}{3} +% \pgfprofilenewforcommand{\pgfmathparse}{1} +% \pgfprofilenewforpgfkey{/forest/split} +% \pgfprofilenewforpgfkey{/forest/nodewalk/reverse} +% \pgfprofilenewforcommand{\forest@Nodewalk}{2} +% \pgfprofilenewforcommand{\pgfkeysalso}{1} +% \makeatother \usepackage{hyperref} \hypersetup{unicode=true,colorlinks=true,linkcolor=blue,citecolor=blue,hyperindex=false} @@ -100,11 +117,11 @@ if index entry type={definition}{ temptoksa/.register=result, hyper, - result/.wrap 2 pgfmath args={% + result/.process=ROw2{result}{argument}{% \texttt{\string\begin\char`\{##1\char`\}}% - \forestoption{argument}% - \texttt{\string\end\char`\{##2\char`\}}% - }{result}{temptoksa}, + ##2% + \texttt{\string\end\char`\{##1\char`\}}% + } }{ hyper } @@ -186,7 +203,7 @@ >{aggregate} \indexset - [form={\texttt{pgfmath} function},for first={format={pgfkey}}] + [form={\texttt{pgfmath} function},for first={format={detokenize,pgfkey}}] >{pgfmath} \indexset @@ -197,9 +214,9 @@ form={}, for first={ for first={ - key+/.pgfmath=argument("!parent"), + key+/.option=!parent.argument, index format={ - result+/.wrap pgfmath arg={\protect\meta{##1 option}}{argument("!parent")} + result+/.process={Ow1} {!parent.argument} {\protect\meta{##1 option}}, }, print format={ if argument={}{}{ @@ -217,9 +234,9 @@ form={}, for first={ for first={ - +key/.pgfmath=argument("!parent"), + +key/.option=!parent.argument, index format={ - +result/.wrap pgfmath arg={\protect\meta{##1 option}}{argument("!parent")} + +result/.process={Ow1} {!parent.argument} {\protect\meta{##1 option}}, }, print format={ if argument={}{}{ @@ -237,10 +254,9 @@ form={}, for first={ for first={ - key/.wrap 2 pgfmath args={##1 ##2}{key}{argument("!parent,parent")}, + key/.process={OOw2} {key} {!parent,parent.argument} {##1 ##2}, index format={ - result+={\space}, - result+/.wrap pgfmath arg={\protect\meta{##1}}{argument("!parent,parent")} + result+/.process={Ow1} {!parent,parent.argument} {\space\protect\meta{##1}}, }, print format={ if argument={}{}{ @@ -259,10 +275,9 @@ form={}, for first={ for first={ - key/.wrap 2 pgfmath args={##2 ##1}{key}{argument("!parent,parent")}, + key/.process={OOw2} {key} {!parent,parent.argument} {##2 ##1}, index format={ - +result={\space}, - +result/.wrap pgfmath arg={\protect\meta{##1}}{argument("!parent,parent")} + +result/.process={Ow1} {!parent,parent.argument} {\protect\meta{##1}\space}, }, print format={ if argument={}{}{ @@ -281,7 +296,7 @@ index key format={result/.expanded=\forestoption{argument} value}, format={result/.expanded=\noexpand\texttt{\forestoption{argument}} value}, for first={format=pgfkey} - ]>{value} + ]>{value of} \indexset[ index key format={result/.expanded=\forestoption{argument} option}, @@ -290,8 +305,13 @@ ]>{option of} \indexset - [form={},for first={format=meta}] - >{meta} + [form={},for first={ + print format={if argument={}{}{ + result+={:\ }, + result+/.option=argument, + }}, + format=meta, + }]>{meta} \indexset[ for first={+key={{cs }},format={pgfkey}} @@ -305,6 +325,10 @@ [for first={format=pgfkey}] >{named nodewalk} +\indexset[ + format={result/.expanded=\noexpand\texttt{process instruction}}, + for first={format=pgfkey} + ]>{processor} {\makeatletter % an dirty patch: \lst@nolig can sneak in the name... \gdef\myexampleindex#1{{\def\lst@nolig{}\lstaspectindex{#1}{}}} @@ -329,7 +353,7 @@ web: \href{http://spj.ff.uni-lj.si/zivanovic/}{http://spj.ff.uni-lj.si/zivanovic/}}} -%\usepackage[trace]{trace-pgfkeys} % silent, stack, trace, verbose +%\usepackage[verbose]{trace-pgfkeys} % silent, stack, trace, verbose %\pgfkeystracelevel{trace} \begin{document} @@ -338,6 +362,7 @@ % short verbatim: | (changes spaces into _) \DeleteShortVerb\| +\def\indexpipe{|} {\catcode`\_=12 \def\marshal{% \lstMakeShortInline[basicstyle=\ttfamily,literate={_}{ }1 {__}{_}1]}% \expandafter}\marshal | @@ -368,7 +393,7 @@ other kinds of) trees. Its main features are \vspace{1cm} -\begin{forestexample}[basicstyle=\ttfamily\scriptsize,layout=tree on top,no label,v sep=1cm,index={content,pgfmath,propagator>if,repeat,append,before drawing tree,y,alias,for step,step>children,edge,before typesetting nodes,tree,s sep,dimen+,l,ancestors,typeset node,nodewalk,readonly option>level,sort by,step>min}] +\begin{forestexample}[basicstyle=\ttfamily\scriptsize,layout=tree on top,no label,v sep=1cm,index={content,pgfmath,conditional>if,repeat,append,before drawing tree,y,alias,for step,step>children,edge,before typesetting nodes,tree,s sep,dimen+,option>l,ancestors,typeset node,nodewalk,readonly option>level,sort by,step>min}] \pgfmathsetseed{14285} \begin{forest} random tree/.style n args={3}{% #1 = max levels, #2 = max children, #3 = max content @@ -444,8 +469,13 @@ can show your appreciation by making a PayPal donation to \url{saso.zivanovic@gu \section{Tutorial} \label{sec:tutorial} -This short tutorial progresses from basic through useful to -obscure \dots +This short tutorial progresses from basic through useful to obscure \dots fortunately, it is not the +only newcomer's source of information on \foRest;: check out +\href{http://mirrors.ctan.org/info/forest-quickstart/ForestQuickstart.pdf}{Forest Quickstart Guide + for Linguists}. Another very useful source of information (and help!) about \foRest; and \TeX\ in +general is \href{http://tex.stackexchange.com}{\TeX\ StackExchange}. Check out the questions tagged +\href{http://tex.stackexchange.com/questions/tagged/forest}{\texttt{forest}}! + \subsection{Basic usage} \label{tut:basic-usage} @@ -529,6 +559,7 @@ typeset (Government Phonology) phonological representations. The style is appli writing its name before the first (opening) bracket of the tree. \begin{forestexample}[label=ex:gp1-frost,code prefix={\def\usepackage[##1]##2{}}] \usepackage[~linguistics~]{forest} + % ... \begin{forest} ~GP1~ [ [O[x[f]][x[r]]] [R[N[x[o]]][x[s]]] @@ -545,9 +576,6 @@ load a library is as shown in the example, by loading the package with an option more information on loading libraries, see \S\ref{ref:package-options}. -(Style \index{GP1} used above is defined in the \keyname{linguistics} -library of the \foRest; package.) - \subsection{Options} \label{tut:options} @@ -556,7 +584,7 @@ properties of the node and the tree. For example, at the end of section~\ref{tut:basic-usage}, we have seen that the \index{GP1} style vertically aligns the parent with the first child. This is achieved by setting option \index{calign} (for -\emph{c}hild-\emph{align}ment) to \index{value=calign>first} (child). +\emph{c}hild-\emph{align}ment) to \index{value of=calign>first} (child). Let's try. Options are given inside the brackets, following the content, but separated from it by a comma. (If multiple options are @@ -564,7 +592,7 @@ given, they are also separated by commas.) A single option assignment takes the form \meta{option name}|=|\meta{option value}. (There are also options which do not require a value or have a default value: these are given simply as \meta{option name}.) -\begin{forestexample}[label=ex:numerals-simple,index={calign,value=calign>first}] +\begin{forestexample}[label=ex:numerals-simple,index={calign,value of=align>first}] \begin{forest} [\LaTeX\ numerals, ~calign=first~ [arabic[1][2][3][4]] @@ -575,7 +603,7 @@ these are given simply as \meta{option name}.) \end{forestexample} The experiment has succeeded only partially. The root node's -children are aligned as desired (so \index{calign}|=|\index{value=calign>first} applied to the +children are aligned as desired (so \index{calign}|=|\index{value of=calign>first} applied to the root node), but the value of the \index{calign} option didn't get automatically assigned to the root's children! \emph{An option given at some node applies only to that node.} In \foRest;, the options @@ -593,9 +621,9 @@ propagator. Observe: ] \end{forest} \end{forestexample} -The value of propagator \index{for step=\index{tree}} is the option string that we -want to process. This option string is propagated to all the nodes in -the subtree\footnote{It might be more precise to call this option +The value of propagator \index{for step=\index{tree}} is a list of keys that we +want to process. This keylist is propagated to all the nodes in +the subtree\footnote{It might be more precise to call \index{for step=\index{tree}} \texttt{for subtree} \dots\@ but this name at least saves some typing.} rooted in the current node (i.e.\ the node where \index{for step=\index{tree}} was given), including the node itself. (Propagator \index{for step=\index{descendants}} is @@ -657,7 +685,8 @@ easiest case of roman numerals: to get them, we can use the (plain) \TeX\ command |\romannumeral|. To change the content of the node, we use option \index{content}. When specifying its new value, we can use |#1| to insert the current content.\footnote{This mechanism is called -\emph{wrapping}. \index{content} is the only option where wrapping works implicitely (simply + \emph{wrapping}. By default, \index{content} is the only \index{autowrapped toks} option, + i.e.\ option where wrapping works implicitely (simply because I assume that wrapping will be almost exclusively used with this option). To wrap values of other options, use handler \index{wrap value}; see~\S\ref{ref:handlers}.} \begin{forestexample}[point={content,delay},index={for step,step>children,content,delay},label=ex:romannumeral] @@ -671,8 +700,8 @@ This example introduces another option: \index{delay}. Without it, the example would get arabic numerals. This is so because of the order in which the options are processed. First, the processing proceeds through the tree in a depth-first, parent-first fashion (first the parent is processed, and then its children, recursively; but see \index{processing order}). Next, -the option string of a node is processed linearly, in the order they were given. (Option -\index{content} is specified implicitely and is always the first.) If a propagator is encountered, +the option string of a node is processed linearly, in the order they were given. Option +\index{content} is specified implicitely and is always the first. If a propagator is encountered, the options given as its value are propagated \emph{immediately}. The net effect is that if the above example contained simply |roman,for_children={content=...}|, the \index{content} option given there would be processed \emph{before} the implicit content options given to the children @@ -687,19 +716,19 @@ Unlike \index{for step=\meta{step}} keys we have met before, \index{delay} is no spatial, but a temporal propagator. Several other temporal propagators options exist, see \S\ref{ref:stages}. -We are now ready to learn about simple conditionals. Every node option has the corresponding -\index{if option=\meta{option}} and \index{where option=\meta{option}} keys. -\index{if option=\meta{option}}|=|\meta{value}\meta{true options}\meta{false options} checks whether -the value of \meta{option} equals \meta{value}. If so, \meta{true options} are -processed, otherwise \meta{false options}. The \index{where option=\meta{option}} keys are -the same, but do this for the every node in the subtree; informally -speaking, |where| = |for_tree| + |if|. To see this in action, -consider the rewrite of the \index{tier} example (\ref{ex:tier-manual}) from above. We don't set -the tiers manually, but rather put the terminal nodes (option -\index{n children} is a read-only option containing the number -of children) on tier \keyname{word}.\footnote{We could omit the braces around \texttt{0} because -it is a single character. If we were hunting for nodes with 42 children, we'd have to write -\texttt{where n children=\{42\}...}.} +We are now ready to learn about simple conditionals.\footnote{See \S\ref{ref:conditionals} for + further information on conditionals, including the generic \index{if} and \index{where}.} Every +node option has the corresponding \index{if option=\meta{option}} and \index{where + option=\meta{option}} keys. \index{if option=\meta{option}}|=|\meta{value}\meta{true + options}\meta{false options} checks whether the value of \meta{option} equals \meta{value}. If +so, \meta{true options} are processed, otherwise \meta{false options}. The \index{where + option=\meta{option}} keys are the same, but do this for the every node in the subtree; informally +speaking, |where| = |for_tree| + |if|. To see this in action, consider the rewrite of the +\index{tier} example (\ref{ex:tier-manual}) from above. We don't set the tiers manually, but rather +put the terminal nodes (option \index{n children} is a read-only option containing the number of +children) on tier \keyname{word}.\footnote{We could omit the braces around \texttt{0} because it is + a single character. If we were hunting for nodes with 42 children, we'd have to write + \texttt{where n children=\{42\}...}.} \begin{forestexample}[index={tier,where option,n children}] \begin{forest} ~where n children~=0{tier=word}{} @@ -714,15 +743,26 @@ it is a single character. If we were hunting for nodes with 42 children, we'd ha \end{forest} \end{forestexample} -Note that you usually don't want to embed a \index{where} conditional in a \index{for step=\index{tree}}, as this will lead to a multiple traversal of many nodes, resulting in a slower execution. -If you're inside a \index{for step=\index{tree}}, you probably want to use \index{if}. +\begin{advise} +\item Note that you usually don't want to embed a \index{where option=...} conditional in a \index{for + step=\index{tree}}, as this will lead to a multiple traversal of many nodes, resulting in a + slower execution. If you're inside a \index{for step=\index{tree}}, you probably want to use + \index{if}. +\end{advise} + + +Finally, let's talk about styles. +(They are not actually defined in the \foRest; package, but rather +inherited from |pgfkeys|.) + + + -Finally, let's talk about styles. Styles are simply collections of -options and/or other keys. (They are not actually defined in the \foRest; package, but -rather inherited from |pgfkeys|.) If you often want to have non-default -parent/child anchors, say south/north as in example (\ref{ex:tier-manual}), you would save some -typing by defining a style. Styles are defined using \PGF;'s handler -|.style|, like shown below.\footnote{Style \index{sn edges} is actually already defined by library \reflibrary{linguistics}. The definition there is a bit more generic.} +At the first approximation, styles are abbreviations: if you +often want to have non-default parent/child anchors, say south/north as in example +(\ref{ex:tier-manual}), you could save some typing by defining a style. Styles are defined using +\PGF;'s handler |.style|, like shown below.\footnote{Style \index{sn edges} is actually already + defined by library \reflibrary{linguistics}. The definition there is a bit more generic.} \begin{forestexample}[index={tier,option>parent anchor,option>child anchor}] \begin{forest} ~sn edges~/~.style~={for tree={ @@ -746,7 +786,7 @@ environment. Use macro \index{forestset} to do this. } \end{lstlisting} -You might have noticed that in the last two examples contain, some keys occurred even before the +You might have noticed that in the last two examples, some keys occurred even before the first opening bracket, contradicting was said at the beginning of this section. This is mainly just syntactic sugar (it can separate the design and the content): such \emph{preamble} keys behave as if they were given in the root node, the only difference (which often does not @@ -754,7 +794,7 @@ matter) being that they get processed before all other root node options, even t \index{content}. If you find yourself writing the same preamble for every tree in your document, -consider redefining style \index{default preamble}, which is implicitely included at the beginning +consider modifying \index{default preamble}, which is implicitely included at the beginning of every preamble. \subsection{Decorating the tree} @@ -834,10 +874,10 @@ errors.) Finally, the most powerful tool in the node reference toolbox: \emph{relative nodes}. It is possible to refer to other nodes which stand in some (most often geometrical) relation to the current node. To -do this, follow the node's name with a \index>{!} and a \emph{node walk} +do this, follow the node's name with a \index>{!} and a \emph{nodewalk} specification. -A node walk is a concise\footnote{Actually, \foRest; distinguishes two kinds of steps in node walks: +A nodewalk is a concise\footnote{Actually, \foRest; distinguishes two kinds of steps in node walks: long-form and short-form steps. This section introduces only short-form steps. See \S\ref{ref:nodewalks}.} way of expressing node relations. It is simply a string of steps, which are represented by single characters, where: \index{ss u} stands for the parent node (up); \index{ss @@ -884,7 +924,7 @@ sibling. \end{forestexample}% \endgroup -The second example uses \TikZ;'s fitting library to compute the +The second example uses \TikZ;'s fitting library (automatically loaded by \foRest;) to compute the smallest rectangle containing node VP, its first child (DP$_2$) and its last grandchild (DP$_3$). The example also illustrates that the \TikZ; code can be specified via the ``normal'' option syntax, i.e.\ as a value @@ -915,19 +955,23 @@ grows down. More generally, however, the direction of growth can change from no controlled by option \index{grow}=\meta{direction}.\footnote{The direction can be specified either in degrees (following the standard mathematical convention that $0$ degrees is to the right, and that degrees increase counter-clockwise) or by the compass directions: \texttt{east}, \texttt{north east}, - \texttt{north}, etc.} The system thus computes and stores the positions of children using a + \texttt{north}, etc.} The system computes and stores the positions of children using a coordinate system dependent on the parent, called an \emph{ls-coordinate system}: the origin is the parent's anchor; l-axis is in the direction of growth in the parent; s-axis is orthogonal to the l-axis (positive side in the counter-clockwise direction from $l$-axis); l stands for \emph{l}evel, -s for \emph{s}ibling. The example shows the ls-coordinate system for a node with |grow=45|. +s for \emph{s}ibling. The example shows the ls-coordinate system for a node with +|grow=45|.\footnote{The axes are drawn using coordinates given in \texttt{forest cs} coordinate + system; the ``manually'' given polar coordinate equivalent is shown in the comment.} -\begin{forestexample}[point=grow,index=grow] +\begin{forestexample}[point=grow,index={grow}] \begin{forest} background tree [parent, grow=45 [child 1][child 2][child 3][child 4][child 5] ] - \draw[,->](-135:1cm)--(45:3cm) node[below]{$l$}; - \draw[,->](-45:1cm)--(135:3cm) node[right]{$s$}; + %\draw[,->](-135:1cm)--(45:3cm) node[below]{$l$}; + \draw[,->](forest cs:l=-1cm,s=0)--(forest cs:l=3cm,s=0) node[below]{$l$}; + %\draw[,->](-45:1cm)--(135:3cm) node[right]{$s$}; + \draw[,->](forest cs:s=-1cm,l=0)--(forest cs:s=3cm,l=0) node[right]{$s$}; \end{forest} \end{forestexample} @@ -956,18 +1000,19 @@ s for \emph{s}ibling. The example shows the ls-coordinate system for a node wit \input{\jobname.tmp} -The l-coordinate of children is (almost) completely under your control, i.e.\ you set what is -often called the level distance by yourself. Simply set option \index{option>l} to change the -distance of a node from its parent. More precisely, \index{option>l}, and the related option +The l-coordinate of children is (almost) completely under your control, i.e.\ you set what is often +called the level distance by yourself. Simply set option \index{option>l} to change the distance of +a node from its parent.\footnote{If setting \index{option>l} seems to have no effect, read about + \index{l sep} further down this section.} More precisely, \index{option>l}, and the related option \index{option>s}, control the distance between the (node) anchors of a node and its parent. The -anchor of a node can be changed using option \index{option>anchor}: by default, nodes are anchored at -their base; see \cite[\S16.5.1]{tikzpgf2.10}.) In the example below, positions of the anchors are -shown by dots: observe that anchors of nodes with the same \index{option>l} are aligned and that the -distances between the anchors of the children and the parent are as specified in the +anchor of a node can be changed using option \index{option>anchor}: by default, nodes are anchored +at their base; see \cite[\S16.5.1]{tikzpgf2.10}.) In the example below, positions of the anchors +are shown by dots: observe that anchors of nodes with the same \index{option>l} are aligned and that +the distances between the anchors of the children and the parent are as specified in the code.\footnote{Here are the definitons of the macros for measuring distances. Args: the x or y -distance between points \#2 and \#3 is measured; \#4 is where the distance line starts (given as an -absolute coordinate or an offset to \#2); \#5 are node options; the optional arg \#1 is the format of -label. (Lengths are printed using package \texttt{printlen}.) + distance between points \#2 and \#3 is measured; \#4 is where the distance line starts (given as + an absolute coordinate or an offset to \#2); \#5 are node options; the optional arg \#1 is the + format of label. (Lengths are printed using package \texttt{printlen}.) \box\codebox} \begin{forestexample}[layout=tree on top,index={for step,tree,tikz,option>l,option>anchor},index>={!}] @@ -1139,8 +1184,8 @@ some child is too high, or the parent is too deep. The first problem is easier situation using a bottom-aligned multiline node. (Multiline nodes can be easily created using |\\| as a line-separator. However, you must first specify the horizontal alignment using option \index{align} (see \S\ref{ref:node-appearance}). -Bottom vertical alignment is achieved by setting \index{base}|=|\index{value=base>bottom}; -the default, unlike in \TikZ;, is \index{base}|=|\index{value=base>top}). +Bottom vertical alignment is achieved by setting \index{base}|=|\index{value of=base>bottom}; +the default, unlike in \TikZ;, is \index{base}|=|\index{value of=base>top}). \begin{forestexample}[point={align,base},index={align,base}] \begin{forest} [parent @@ -1159,7 +1204,7 @@ needed to decrease the level distance? And nothing happened, like below on the l you used lots of parenthesis in your nodes? And got a strange vertical misalignment, like below on the right? Then rest assured that these (at least) are features not bugs and read \S\ref{tut:defaults}. -\begin{forestexample}[layout=tree on top,v sep=-55ex,code left skip=-3cm,label=ex:misalignments,index={option>phantom,for step,step>children,fit,propagator>for,baseline,edge,descendants,content,pgfmath,ss 1}] +\begin{forestexample}[layout=tree on top,v sep=-55ex,code left skip=-3cm,label=ex:misalignments,index={option>phantom,for step,step>children,fit,baseline,edge,descendants,content,pgfmath,ss 1}] \begin{forest} [,phantom,for children={l sep=1ex,fit=band, for 1={edge'=,l=0},baseline} @@ -1274,18 +1319,18 @@ Setting only a default \index{l sep} thus does not work well enough in general. is true for the reverse possibility, setting a default \index{option>l} (and leaving \index{l sep} at 0). In the example below, the depth of the multiline node (anchored at the top line) is such that the child--parent edges are just too short if the level distance is kept constant. Sometimes, misalignment is much preferred \dots -\begin{forestexample}[index={align,{value=align>center},for step,tree,l sep}] +\begin{forestexample}[index={align,{value of=align>center},for step,tree,l sep}] \mbox{}\begin{forest} - [default + [default,baseline [first child[a][b][c]] - [second child\\[-1ex]\scriptsize(a copy), + [{second child\\[-1ex]\scriptsize(a copy)}, align=center[a][b][c]] ] - \end{forest}\\ + \end{forest}\quad \begin{forest} for tree={l sep=0} - [{\texttt{l sep}=0} + [{\texttt{l sep}=0},baseline [first child[a][b][c]] - [second child\\[-1ex]\scriptsize(a copy), + [{second child\\[-1ex]\scriptsize(a copy)}, align=center[a][b][c]] ] \end{forest} @@ -1308,19 +1353,20 @@ and the standard node needs to be modified. But for many applications, includin indices, the default works. The standard node can be changed using macro \index{forestStandardNode}; -see \ref{ref:standard-node}. +see \ref{ref:standard-node}. +% TODO: primer? ali raje po spremembi interfaceja \subsection{Advanced option setting} \label{tut:advanced-option-setting} -We have already seen that the value of options can be manipulated: in (\ref{ex:romannumeral}) we have -converted numeric content from arabic into roman numerals using the \emph{wrapping} mechanism -|content=\romannumeral#1|; in (\ref{ex:l*}), we have tripled the value of |l| -by saying |l*=3|. In this section, we will learn about the mechanisms for setting and -referring to option values offered by \foRest;. +We have already seen that the value of options can be manipulated: in (\ref{ex:romannumeral}), we +have converted numeric content from arabic into roman numerals using the \emph{wrapping} mechanism +|content=\romannumeral#1|; in (\ref{ex:l*}), we have tripled the value of |l| by saying |l*=3|. In +this section, we will learn more about the mechanisms for setting options and referring to their +values. One other way to access an option value is using macro \index{forestoption}. The macro takes a -single argument: an option name. (For details, see \S\ref{sec:option-reading}.) In the +single argument: an option name. In the following example, the node's child sequence number is appended to the existing content. (This is therefore also an example of wrapping.) \begin{forestexample}[label=ex:forestoption,index={option>phantom,delay,for step,descendants,content,readonly option>n,forestoption}] @@ -1331,11 +1377,11 @@ therefore also an example of wrapping.) \end{forest} \end{forestexample} -However, only options of the current node can be accessed using \index{forestoption}. To -access option values of other nodes, \foRest;'s extensions to the \PGF;'s mathematical library -|pgfmath|, documented in \citep[part VI]{tikzpgf2.10}, must be used. To see |pgfmath| in action, +However, only options of the current node can be accessed using \index{forestoption}. Possibly the simplest way to +access option values of other nodes is to use \foRest;'s extensions to the \PGF;'s mathematical library +|pgfmath|, documented in \citep[part VI]{tikzpgf2.10}. To see |pgfmath| in action, first take a look at the crazy tree on the title page, and observe how the nodes are -rotated: the value given to (\TikZ;) option \texttt{rotate} is a full-fledged |pgfmath| expression +rotated: the value given to option \index{rotate} is a full-fledged |pgfmath| expression yielding an integer in the range from $-30$ to $30$. Similiarly, \index{dimen+=l} adds a random float in the $[-5,5]$ range to the current value of \index{option>l}. @@ -1370,7 +1416,7 @@ the current node is just a short-hand notation for \texttt{option\string_name()} --- note that in some contexts, like preceding \texttt{+} or \texttt{-}, the short form does not work! (The same seems to be true for all pgfmath functions with ``optional'' arguments.)} In the next example, we -rotate the node based on the content of its parent. +rotate the node based on the content of its parent (\index{short step>u} means `up'). \begin{forestexample}[index={delay,for step,descendants,content,ss u},index>={!}] \begin{forest} delay={for descendants={rotate=content~("!u")~}} @@ -1380,15 +1426,92 @@ rotate the node based on the content of its parent. Note that the argument of the option function is surrounded by double quotation marks: this is to prevent evaluation of the relative node name as a |pgfmath| function --- which it is not. -Handlers \index{wrap pgfmath arg} and \index{wrap $n$ pgfmath args} -(for $n=2,\dots,8$) combine the wrapping mechanism with the |pgfmath| evaluation. The -idea is to compute (most often, just access option values) arguments using |pgfmath| and then -wrap them with the given macro. Below, this is used to include the number of parent's children in -the index. -\begin{forestexample}[index={option>phantom,delay,for step,descendants,content,readonly option>n,n children,wrap $n$ pgfmath args},index>={!}] +For further ways to access option values, see \S\ref{tut:wrapping}. Here, we continue by introducing +\emph{relative node setting}: write \index{relative node name}|.|\meta{option}|=|\meta{value} to set +the value of \meta{option} of the specified relative node. Important: computation of the value is +done in the context of the original node. The following example defines style \keyname{move} which +not only draws an arrow from the source (the current node) to the target, but also moves the content +of the source to the target (leaving a trace). Note the difference between |#1| and |##1|: |#1| is +the argument of the style \keyname{move} (a node walk determining the target), while |##1| is the +original option (in this case, \indexex{option>content}) value. +\begin{forestexample}[index={for step,tree,calign,tikz,delay,content},index>={!}] + \begin{forest} + for tree={calign=fixed edge angles}, + move/.style={ + tikz={\draw[->] () to[out=south west,in=south] (#1);}, + delay={~#1.content~={##1},content=$t$}}, + [CP[][C'[C][\dots[,phantom][VP[DP][V'[V][DP,move=!r1]]]]]] + \end{forest} +\end{forestexample} + +\begin{forestexample}[index={if option,n children,content,for step,step>children,delay,pgfmath},index>={!},basicstyle=\scriptsize\ttfamily,layout=export] + \begin{forest} + calc/.style={if n children={0}{}{content=0,for children={calc,~!u.content~/.pgfmath=int(content("!u")+content())}}}, + delay=calc, + [[[3][4][5]][[3][9]][8][[[1][2][3]]]] + \end{forest} +\end{forestexample} + +In the following example, the content of the branching nodes is computed by \foRest;: a branching +node is a sum of its children. The algorithm visits each node (but the root node) and adds its +content to the content of the parent. Note that as the computation must proceed bottom-up, +\index{for step=\index{descendants children-first}} propagator is used to walk through the +tree.\footnote{It would be possible to emulate \index{for step=\index{descendants children-first}} + by defining a recursive style, as was done in this manual for versions of the package prior to + introduction of the bottom-up propagator. The following code produces identical result as the code + in the main text. + + \box\codebox} + +\begin{forestexample}[index={if option,n children,content,for step,step>children,delay,pgfmath},index>={!}] + \begin{forest} + delay={ + where n children={0}{}{content=0}, + for descendants children-first={ + ~!u.content~/.pgfmath=int(content("!u")+content())} + } + [[[3][4][5]][[3][9]][8][[[1][2][3]]]] + \end{forest} +\end{forestexample} + +Actually, for common computations such as summing things up, \foRest; provides an easier way to do it: aggregate functions (\S\ref{ref:aggregate-functions}). Below, aggregate function \index{sum}, defined as |pgfkeys| handler, walks through the \index{step>children} (second argument) of the current node, summing up their \index{content} (first argument) and stores the result as the \index{content} of the current node (because \index{content} is the handled key). + +\begin{forestexample}[index={sum,aggregate postparse,for step,tree children-first,delay,n children,if option,content,step>children}] + \begin{forest} + delay={ + aggregate postparse=int, + for tree children-first={ + if n children={0}{}{ + content/~.sum~={content}{children} + } + } + } + [[[3][4][5]][[3][9]][8][[[1][2][3]]]] + \end{forest} +\end{forestexample} + +\subsection{Wrapping} +\label{tut:wrapping} + +We have already seen examples of inserting option values into other expressions. In example +(\ref{ex:romannumeral}), we have wrapped the value of the option being assigned to (|#1| stood for +the current value of option \index{content}); example (\ref{ex:forestoption}) additionally wrapped +the value of option \index{readonly option>n} (of the current node) using macro \index{forestoption}. In general, +\foRest; offers two ways to perform computations (from simple option value lookups to +complicated formulas) and insert their results into another expression (of any kind: \TeX\ code, +|pgfkeys| keylist, |pgfmath| expression, etc.). + +Historically, the first \foRest;'s mechanism that offered wrapping of computed values were handlers +\index{wrap pgfmath arg} and \index{wrap $n$ pgfmath args} (for $n=2,\dots,8$), which combine the +wrapping mechanism with the |pgfmath| evaluation. The idea is to compute (most often, just access +option values) arguments using |pgfmath| and then wrap them into the given macro body (marked below) +using \TeX's parameters (|#1| etc.). Below, this is used to subscript the contents of a node with +its sequential number and the number of parent's children. +\begin{forestexample}[index={option>phantom,delay,for step,descendants,content,readonly option>n,n children,wrap $n$ pgfmath args},index>={!},label=ex:pgfmathwrap] \begin{forest} [,phantom,delay={for descendants={ - ~content/.wrap 3 pgfmath args= - {#1$_{#2/#3}$}{content}{n}{n_children("!u")}~}} + content/.wrap 3 pgfmath args= + ~{#1$_{#2/#3}$}~ + {content}{n}{n_children("!u")}}} [c][o][u][n][t]] \end{forest} \end{forestexample} @@ -1398,15 +1521,15 @@ underscores. As another example, let's make the numerals example (\ref{ex:numerals-simple}) a bit fancier. The numeral type is read off the parent's content and used to construct the appropriate control -sequence (|\@arabic|, |\@roman| and |\@alph|). (Also, the numbers are not specified in content -anymore: we simply read the sequence number \index{readonly option>n}. And, to save some horizontal space for the -code, each child of the root is pushed further down.) +sequence (|\@arabic|, |\@roman| and |\@alph|). (The numbers are not specified in content +anymore: we simply read the sequence number \index{readonly option>n}.) \begin{forestexample}[index={delay,where option,readonly option>level,content,readonly option>n,for step,step>children,option>l,wrap $n$ pgfmath args},index>={!}] \begin{forest} - delay={where level={2}{~content/.wrap 2 pgfmath args= - {\csname @#1\endcsname{#2}}{content("!u")}{n}~}{}}, + delay={where level={2}{content/.wrap 2 pgfmath args= + {\csname @#1\endcsname{#2}} + {content("!u")}{n}}{}}, for children={l*=n}, - [\LaTeX numerals, + [\LaTeX\ numerals, [arabic[][][][]] [roman[][][][]] [alph[][][][]] @@ -1414,73 +1537,121 @@ code, each child of the root is pushed further down.) \end{forest} \end{forestexample} -The final way to use |pgfmath| expressions in \foRest;: |if| clauses. In -section~\ref{tut:options}, we have seen that every option has a corresponding \index{if option=\meta{option}} -(and \index{where option=\meta{option}} key. However, these are just a matter of convenience. The full -power resides -in the general \index{conditional>if} conditional, which takes three arguments: -|if=|\meta{condition}\meta{true options}\meta{false options}, where \meta{condition} can be any -|pgfmath| expression -(non-zero means true, zero means false). (Once again, propagator \index{propagator>where} is an abbreviation -for \index{for step=\index{tree}}|={|\index{conditional>if}|=...}|.) In the following example, \index{conditional>if} option -is used to orient the -arrows from the smaller number to the greater, and to color the odd and even numbers differently. - -\forestset{random tree/.style n args={3}{% #1=max levels, #2=max children, #3=max content - content/.pgfmath={random(0,#3)}, - if={#1>0}{repeat={random(0,#2)}{append={[,random tree={#1-1}{#2}{#3}]}}}{}}} -\begin{forestexample}[index={before typesetting nodes,for step,descendants,conditional>if,content,edge,edge label,tree},index>={!},point=if] - \pgfmathsetseed{314159} +Invoking |pgfmath| is fairly time consuming and using it to do nothing but retrieve an option value +seems a bit of an overkill. To remedy the situation, argument processor +(\S\ref{ref:argument-processor}) was introduced in \FoRest; v2.0 and considerably expanded in v2.1. +One way to invoke it is using handler \index{handler>process}. + +The argument processor takes a sequence of instructions and an arbitrary number of arguments, +transforms the given arguments according to the instructions, and feeds the resulting list of +arguments into the handled key. + +An instruction is given by a single-character code. The simplest instructions are: +\index{processor>O}, which expects its argument to be an option name (possibly preceded by a +\index{relative node name}|.| to access the option value of a non-current node) and returns the +value of the option; \index{processor>R}, which does the same for registers; and \index{processor>noop}, which +leaves the argument unchanged. + +In the following example, we define style |test| taking four arguments and call it by providing +the arguments via \index{handler>process}. The instruction string |ROO__| tells the argument processor that +the first argument is the value of (scratch) register \indexex{temptoksa}, the second the value of +option \indexex{n children} at the current node, the third the value of option \indexex{content} of +the second child of the current node, and the fourth just a plain string. Macro |test| is thus +actually invoked with argument list |{Hello}{3}{Jane}{Goodbye}|. + +\begin{forestexample}[index={handler>process,processor>noop,processor>R,processor>O,delay,content,n +children,temptoksa}] \begin{forest} - before typesetting nodes={ - for descendants={ - if={content()>content("!u")}{edge=->}{ - if={content()<content("!u")}{edge=<-}{}}, - edge label/.wrap pgfmath arg= - {node[midway,above,sloped,font=\scriptsize]{+#1}} - {int(abs(content()-content("!u")))} - }, - for tree={circle,if={mod(content(),2)==0} - {fill=yellow}{fill=green}} - } - [,random tree={3}{3}{100}] + test/.style n args={4}{align=center, + content={#1!\\I have #2 children.\\One of them is #3.\\#4!}} + [,delay={temptoksa=Hello, + test/.process={~ROO_~}{temptoksa}{n children}{!2.content}{Goodbye}} + [John][Jane][Joe]] \end{forest} \end{forestexample} -This exhausts the ways of using |pgfmath| in forest. We continue by introducing \emph{relative -node setting}: write \index{relative node name}|.|\meta{option}|=|\meta{value} to set the -value of \meta{option} of the specified relative node. Important: computation (pgfmath or wrap) of -the value is -done in the context of the original node. The following example defines style \keyname{move} which -not only draws an arrow from the source to the target, but also moves the content of the source -to the target (leaving a trace). Note the difference between |#1| and |##1|: |#1| is the argument -of the style \keyname{move}, i.e.\ the given node walk, while |##1| is the original option value -(in this case, content). -\begin{forestexample}[index={for step,tree,calign,tikz,delay,content},index>={!}] +To wrap using the argument processor, use instruction \index{processor>w}. Unless wrapping a single +argument, this instruction should be followed by a number indicating the number of arguments +consumed. \index{processor>w} will take the required number of arguments from the list of already +processed arguments and wrap them in the macro body given as the next (yet unprocessed) argument. + +The following example has the same result as example (\ref{ex:pgfmathwrap}). Note that the +order of the wrapper-macro body and the arguments is different for \index{handler>process} and \index{wrap + $n$ pgfmath args}. (Experience shows that \index{handler>process}'s order is easier on the eyes.) The +example also illustrates that (i) the instructions need not be enclosed in braces and (ii) that +repetition of an argument processor instruction can be indicated by appending a number to the +instruction: thus |O3| below means the same as |OOO|. + +\begin{forestexample}[index={option>phantom,delay,for step,descendants,content,readonly option>n,n children},index>={!}] + \begin{forest} [,phantom,delay={for descendants={ + content/.process=~O3 w3~ + {content}{n}{!u.n children} + {#1$_{#2/#3}$} + }} + [c][o][u][n][t]] + \end{forest} +\end{forestexample} + +Note that the order of the wrapper-macro body and the arguments is different for +\index{handler>process} and \index{wrap $n$ pgfmath args}. Experience shows that +\index{handler>process}'s order is easier on the eyes. The example also illustrates that the +instructions need not be enclosed in braces and that repetition of an argument processor instruction +can be indicated by appending a number to the instruction: |O3| above is equivalent to |OOO|. + +% \begin{forestexample}[index={process,processor>w}] +% \begin{forest} +% [root,delay={align=center, +% content/.process={OO ~w2~} +% {n children}{content} +% {This node has #1 children.\\It's original content is ``#2''.} +% }] +% \end{forest} +% \end{forestexample} + +\index{wrap $n$ pgfmath args} always returns a single braced expression and is thus a bit cumbersome +to use when the handled key expects multiple arguments: the trick is to enclose the expected +argument list in extra braces (marked in the code below). As \index{handler>process} can return multiple +arguments, there is no need for such a workaround. See the following example for comparison of the +two methods. + +\begin{forestexample}[index={for step,step>name,handler>process,processor>O,processor>w,wrap $n$ pgfmath args}] \begin{forest} - for tree={calign=fixed edge angles}, - move/.style={ - tikz={\draw[->] () to[out=south west,in=south] (#1);}, - delay={~#1.content~={##1},content=$t$}}, - [CP[][C'[C][\dots[,phantom][VP[DP][V'[V][DP,move=!r1]]]]]] + [,phantom + [pgfmath[2,delay={for n/.wrap 2 pgfmath args= + ~{~{#1}{content=#2,draw}~}~ + {content}{content("!u")} + } [x][x][x][x]]] + [process[3, delay={for n/.process= + {O Ow1}{content} + {!u.content}{content=#1,draw} + } [x][x][x][x]]] + ] \end{forest} \end{forestexample} -In the following example, the content of the branching nodes is computed by \foRest;: a branching -node is a sum of its -children. Besides the use of the relative node setting, this example notably uses a recursive -style: for each child of the node, style \keyname{calc} first applies itself to the child and then -adds the result to the node; obviously, recursion is made to stop at terminal nodes. -\begin{forestexample}[index={if option,n children,content,for step,step>children,delay,pgfmath},index>={!}] +A single \index{handler>process} invocation can perform multiple wrappings. The numbering of arguments of +each wrapping starts at |#1|. In the example below, \index{for step=\index{nodewalk}} takes two +arguments, a nodewalk and a list of nodekeys. Each is produced by an independent wrapping (wrap bodies +are marked in the code). + +\begin{forestexample}[index={handler>process,processor>R,processor>w,for step,nodewalk,+toks,content}] \begin{forest} - calc/.style={if n children={0}{}{content=0,for children={ - calc,~!u.content~/.pgfmath=int(content("!u")+content())}}}, - delay=calc, - [[[3][4][5]][[3][9]][8][[[1][2][3]]]] + declare toks register=prefix, + declare count register=level to prefix, + prefix=X-, + level to prefix=1, + delay={ + for nodewalk/.process=Rw Rw + {level to prefix}{~level=#1~} + {prefix}{~+content=#1~} + } + [0[1[2]][3[4][5]][6[7][8][9]]] \end{forest} \end{forestexample} + + \subsection{Externalization} \label{tut:externalization} @@ -1541,7 +1712,7 @@ the result, the token following the action character was expanded before the par The action character is not hard coded into \foRest;. Actually, there is no action character by default. (There's enough special characters in \foRest; already, anyway, and the situations where -controlling the expansion is preferable to using the pgfkeys interface are not numerous.) It is +controlling the expansion is preferable to using the |pgfkeys| interface are not numerous.) It is defined at the top of the example by processing key \index{action character} in the |/bracket| path; the definition is local to the \TeX\ group. @@ -1608,7 +1779,7 @@ sticked in front of the expansion. \label{sec:reference} This section documents all publicly exposed keys and macros defined by the core package. All other -commands defined by the package (see the implementation typeset in |forest.doc|) are considered +commands defined by the package (see the implementation typeset in |forest.pdf|) are considered internal and might change without prior notice or compatibility support. \subsection{Package loading and options} @@ -1672,23 +1843,26 @@ If at all possible, each backwards incompatible change is given a key in the |co step=\meta{step}}, where a propagator could not fail. While each compatibility feature can be enabled individually, they are grouped for ease of use. To -load compatibility features since version |x|[|.y|[|.z|]], write |compat=x|[|.y|[|.z|]]|-all| or +load compatibility features since the last version of form +|x|[|.y|[|.z|]], write |compat=x|[|.y|[|.z|]]|-all| or |compat=x|[|.y|[|.z|]]|-most|. The former enables all compatibility features since that release, the latter only those that are guaranteed to not disrupt any new functionality of the package. To load all compatibility features since the last major release (|x| in |x.y.z|), write -|compat=|\indexdef{option of=compat>all}; to load most of them, write |compat=|\indexdef{option - of=compat>most} or simply |compat|. +|compat=|\indexdef{value of=compat>all}; to load most of them, write |compat=|\indexdef{value of=compat>most} or simply |compat|. + +To enable multiple compatibility features, either use this option multiple times, or provide it with +a comma-separated list of compatibility features. (Surround the list by braces.) Specifying this option also defines macro \indexdef{macro>forestcompat} (taking the same arguments as the package option) which can be used to enable compatibility features locally, within the document body. To enable compatibility mode but not enable any specific compatibility feature for -the entire document, write |compat=|\indexdef{option of=compat>none} as a package option. +the entire document, write |compat=|\indexdef{value of=compat>none} as a package option. For a list of compatibility features, see \S\ref{sec:changelog}. By default, the package warns when a compatibility feature is used. Disable this behaviour by -|compat=|\indexdef{option of=compat>silent}. +|compat=|\indexdef{value of=compat>silent}. \indexitem(true){package option>tikzcshack}|=|\alternative{true,false} @@ -1705,8 +1879,9 @@ Prints out some debugging info to the log file. When given no argument, prints available information, otherwise only the information on the listed (comma-separated) debug categories. The available categories are listed below. \begin{syntax} - \indexitem{option of=debug>nodewalks} - \indexitem{option of=debug>dynamics} + \indexitem{value of=debug>nodewalks} + \indexitem{value of=debug>dynamics} + \indexitem{value of=debug>process} \end{syntax} \end{syntax} @@ -1744,11 +1919,14 @@ available information, otherwise only the information on the listed (comma-separ } \end{forestexample}} - Using \meta{config}, it is possible to configure behaviour of the environment/macro prior to - application of \index{style>stages}. The following keys are defined. +\meta{config} is a keylist that configures the behaviour of the environment/macro. The +configuration is the first operation that the environment/macro does; it precedes even the reading +of the tree specification. Currently, \meta{config} accepts only one key: \begin{syntax} - \indexitem{option of=forest>stages}|=|\meta{style definition} overrides the contents of style - \index{style>stages} for the current environment/macro. + \indexitem{option of=forest>stages}|=|\meta{keylist} + + By default, after reading the tree specification, \foRest; executes style \index{style>stages}. + If key |stages| is used in \meta{config}, \meta{keylist} is executed instead. \end{syntax} \indexitem{macro>forestset}\marg{keylist} @@ -1838,7 +2016,7 @@ By redefining the following two keys, the bracket parser can be used outside \fo computed so that the nodes don't overlap. That's difficult. The result: option \index{option>s} is set for all nodes. (Sometimes, the value of \index{option>l} is adjusted as well.) \item\label{step:compute-xy} Absolute positions, or rather, positions of the nodes relative to the - root node are computed. That's easy. The result: options \index{x} and \index{y} are + root node are computed. That's easy. The result: options \index{option>x} and \index{y} are set. \item\label{step:draw-tree} The \TikZ; code that will draw the tree is produced and executed. (The nodes are drawn by using the boxes typeset in step~\ref{step:typeset-nodes}.) @@ -1858,7 +2036,7 @@ better. Second, the execution of the processing stages \ref{step:given-options}--\ref{step:draw-tree} is \emph{completely} under user's control. To facilitate adjusting the processing flow, the approach -is twofold. The outer level: \foRest; initiates the processing by executing style \keyname{stages}, +is twofold. The outer level: \foRest; initiates the processing by executing style \index{style>stages}, which by default executes the processing stages \ref{step:given-options}--\ref{step:draw-tree}, preceding the execution of each but the first stage by processing the keys embedded in temporal propagators \keyname{before ...} (see \S\ref{ref:temporal-propagators}). The inner level: each @@ -1930,13 +2108,13 @@ processing flow. (Experimental, use with care, especially when combining with tier alignment.) \indexitem{stage>compute xy} Computes the positions of the nodes in the subtree relative to the - current node. The results are stored into options \index{x} and \index{y}. The current node's - \index{x} and \index{y} remain unchanged. + current node. The results are stored into options \index{option>x} and \index{y}. The current node's + \index{option>x} and \index{y} remain unchanged. \indexitem{stage>draw tree} \itemnosep \indexitem{stage>draw tree'} - Produces and executed the \TikZ; code that draws the (sub)tree rooted in the current node. + Produces and executes the \TikZ; code that draws the (sub)tree rooted in the current node. The procedure uses the node boxes typeset by \index{typeset nodes} or friends. The |'| variant includes the node boxes in the picture using \cmdname{copy}, not \cmdname{box}, thereby preserving @@ -1968,7 +2146,8 @@ processing flow. Dynamic creation of nodes happens between the cycles. The options given to the dynamically created nodes are implicitely delayed and thus processed at the end of the next cycle. - + + This key is primarily intended for use within \index{style>stages}. The calls of this key should \emph{not} be nested, and it should not be embedded under \index{process keylist'} or \index{process keylist register}. @@ -2027,22 +2206,23 @@ It is safe to embed this key within \index{process keylist} and (all) friends. This key is safe to use within \index{process keylist}, \index{process keylist'} and \index{process keylist register}. -\indexitem(tree){nodewalk style>processing order}|=|\meta{nodewalk} +\indexitem(tree){nodewalk style>processing order}|/.nodewalk style=|\meta{nodewalk} Redefine this style to change the default order in which \index{process keylist} processes a keylist option. For example, to process the nodes in a child-first fashion, write \begin{lstlisting} - for nodewalk={processing order/.style={tree children first}}{} + processing order/.nodewalk style=tree children first \end{lstlisting} -Note that this is a \emph{nodewalk} style, so it must be defined during a nodewalk. +Note that this is a \emph{nodewalk} style, so it must be defined either using |.style| handler +during a nodewalk or using \index{nodewalk style}. -\indexitem(processing order)[form={processing order}]{word suffix=keylist option>nodewalk style>processing order=\meta{keylist option}}|=|\meta{nodewalk} +\indexitem(processing order)[form={processing order}]{word suffix=keylist option>nodewalk style>processing order=\meta{keylist option}}|/.nodewalk style=|\meta{nodewalk} Redefine this style to change the \index{process keylist} processing order for a specific \meta{keylist option}. For example, to process \index{before drawing tree} options in the child-first fashion, leaving the processing of other |before ...| keylists untouched, write \begin{lstlisting} - for nodewalk={before drawing tree processing order/.style={tree children first}}{} + before drawing tree processing order/.nodewalk style=tree children first \end{lstlisting} \indexitem{node key>do dynamics} Experimental. Perform pending dynamic tree operations. @@ -2055,12 +2235,12 @@ child-first fashion, leaving the processing of other |before ...| keylists untou \label{ref:temporal-propagators} Temporal propagators delay processing of given keys until some other point in the processing of the -tree. There are three kinds of temporal propagators. Most of the |before_...| and |after_...| -propagators defer the processing of the given keys to a hook just before some stage in the workflow -(\S\ref{ref:stages}). \index{before packing node} and \index{after packing node} are special as -they fire \emph{during} the packing stage. The \keyname{delay} propagator is ``internal'' to the -current hook: the keys in the hook are processed cyclically, and \keyname{delay} delays the -processing of the given keys until the next cycle. +tree. There are three kinds of temporal propagators. Most of the propagators have the form +|before_...| and defer the processing of the given keys to a hook just before some stage in the +workflow (\S\ref{ref:stages}). \index{before packing node} and \index{after packing node} are +special as they fire \emph{during} the packing stage. The \index{delay} propagator is +``internal'' to the current hook: the keys in the hook are processed cyclically, and \keyname{delay} +delays the processing of the given keys until the next cycle. Formally, temporal propagators are keylist options (except \index{delay n}, which is a style), so augmented assignments are possible (\S\ref{sec:option-setting}). @@ -2136,7 +2316,7 @@ All temporal propagators can be nested without limit. the processing of the \meta{keylist} given to the node to until just after \emph{this specific node} is packed. -\begin{forestexample}[index={after packing node,no edge,calign,value=calign>first,option>l,l sep,content format,content,if option,n children,pgfmath,option>s,max x,min x,for step,step>children,wrap pgfmath arg,typeset node,dimen+=s}] +\begin{forestexample}[index={after packing node,no edge,calign,value of=calign>first,option>l,l sep,content format,content,if option,n children,pgfmath,option>s,max x,min x,for step,step>children,wrap pgfmath arg,typeset node,dimen+=s}] \forestset{box/.style={ draw, no edge, l=0, l sep=1.5ex, calign=first, anchor=base west, @@ -2335,6 +2515,9 @@ declaration mechanism (\S\ref{sec:option-declaring}). \dots) \end{advise} +By default, unknown keys are assumed to be \TikZ; keys and are forwarded to \index{node options}. +This behaviour can be changed using \index{unknown to}. + The following subsections list the node keys which are not described elsewhere (see above): spatial propagators (\S\ref{ref:spatial-propagators}) and general-purpose node keys, i.e.\ those which don't deal with tree formatting (\S\ref{sec:node-keys-various}). @@ -2345,25 +2528,33 @@ deal with tree formatting (\S\ref{sec:node-keys-various}). Spatial propagators pass the given \meta{keylist} to other node(s) in the tree. +Spatial propagation does not change the current node: after visiting the nodes the keys are +propagated to, a spatial propagator (silently, using a so-called fake step) returns to the origin of +the embedded nodewalk. + \FoRest; provides many spatial propagators. Almost all of them are built from long-form nodewalk -steps using prefix \index{for step}. This is why the list below is so short: it only documents -this prefix and the exceptions. For the list of nodewalk steps, see \S\ref{ref:nodewalks}. +steps using prefix \index{for step}. This is why the list below is so short: it only documents this +prefix and the exceptions. For the list of nodewalk steps, see \S\ref{ref:nodewalks}, in particular +\S\ref{ref:single-step-keys} for single-step keys and \S\ref{ref:multi-step-keys} for multi-step +keys. -Spatial propagation does not change the current node: after visiting the nodes the keys are -propagated to, a spatial propagator (silently) returns to the origin of the embedded nodewalk. \begin{syntax} -\indexitem{word prefix=step>propagator>for=\meta{step}}|=|\meta{arg$_1$}|...|\meta{arg$_n$}\meta{keylist} +\indexitem{word prefix=step>propagator>for=\meta{step}}|=|\meta{arg$_1$}|...|\meta{arg$_n$}\meta{keylist: every-step} +\itemnosep +\indexitem[not short]{word prefix=step>propagator>for=\index{nodewalk}}|=|\meta{nodewalk}\meta{keylist: every-step} +\itemnosep +\indexitem[not short]{word prefix=step>propagator>for=\index{nodewalk key>Nodewalk}}|=|\meta{keylist: config}\meta{nodewalk}\meta{keylist: every-step} Walks the (single- or multi-step) \meta{step} from the current node and executes the given \meta{keylist} at every visited node. The current node remains unchanged. - \meta{step} must be a long-form nodewalk step. If it has any arguments, they should be given - before the keylist, with one exception: \meta{keylist: every-step} arguments of embedded nodewalks - should be omitted, as it makes no sense to provide the every-step keylist twice. + \meta{step} must be a long-form nodewalk step. If it has any arguments, they + (\meta{arg$_1$}|...|\meta{arg$_n$}) should be given before every-step \meta{keylist}, with two + exceptions: embedded nodewalk steps (\index{step>Nodewalk} and \index{nodewalk}) already require + the \meta{keylist: every-step} argument, so it should be omitted, as it makes no sense to provide + the every-step keylist twice. - For details on nodewalk steps, see \S\ref{ref:nodewalks}. - Examples: \begin{itemize} \item |for_parent={l_sep+=3mm}| @@ -2372,6 +2563,40 @@ propagated to, a spatial propagator (silently) returns to the origin of the embe \item |for_tree={s_sep+=1em}| \end{itemize} +\long\def\printbigbadforlist#1{% + {% + \tikzexternaldisable + \bracketset{action character=!}% + \begin{forest}(stages={ + process keylist=given options, + for root'={ + sort by={>O+t+c{content}}, + %sort=children, + temptoksa={}, + for sort={children}{ + TeX and memoize/.process=ROw2{temptoksa}{content}{####1\texttt{for\space}\index{step>####2}}, + temptoksa={,\space}, + }, + } + }) + [!\bigbadforlist[nodewalk][nodewalk'][Nodewalk]] + \end{forest}% + }% +}% +\makeatletter +\forest@memoize\printbigbadforlist +\makeatother + +{\tolerance=10000 +Here's the big list of all spatial propagators built with prefix |for|: +% to update, +% - uncomment \appto\bigbadforlist{[#1]} in define long step in forest.dtx +% - delete line \forest@memo@load {forest@memo@\printbigbadforlist ... in forest-doc.memo +\printbigbadforlist{}. +For details on nodewalk steps, see \S\ref{ref:nodewalks}. + +} + \indexitem{propagator>for tree'}|=|\meta{keylist 1}\meta{keylist 2} A ``combination'' of \index{for step=\index{tree children-first}} and \index{for step=\index{tree}}. @@ -2398,11 +2623,13 @@ Configures and executes the \meta{nodewalk}. This key is a nodekey-space copy o \item Use this key carefully as it can change the current node! \item The envisioned purpose of this key is to change the current node within the every-step keylist of (an outer) nodewalk, where only node keys are accepted. The config defaults - (independent every-step, shared history) are set to facilitate that purpose. + (independent every-step, shared history) are set to facilitate that purpose. But it can also be + used as a simple node key, of course. \end{advise} -\indexitem{node key>node walk}|=|\meta{node walk} \textbf{Deprecated!!!} Please use \index{for - step=\index{nodewalk}} in new code. From the old documentation: +\indexitem{node key>node walk}|=|\meta{node walk} \textbf{Deprecated!!!} Requires + \index{compat}|=1.0-nodewalk|. Please use \index{for step=\index{nodewalk}} in new code. From the + old documentation: \begin{quote} This is the most general way to use a \meta{node walk}. @@ -2491,6 +2718,10 @@ store the given content using \meta{key}|=|\meta{content}. not need to be doubled: you can freely copy and paste your keylists between the node options of the root node, the preamble and the default preamble. The only difference will be the order of execution: first default preamble, then preamble, and finally the root node's options. + +\indexitem{node key>save and restore register}|=|\meta{register}\meta{keylist} + +Restores the current value of \meta{register} after executing the \meta{keylist}. \indexitem{node key>split}|=|\meta{toks}\meta{separator}\meta{keylist} \itemnosep @@ -2502,14 +2733,42 @@ Split \meta{toks} or the value of \meta{option} or \meta{register} at occurrence \meta{separator} (which must be a single token), and process the keys in \meta{keylist} with the pieces of the split token list as arguments, in the order given. - The keys in \meta{keylist} can be any valid keys, including augmented assignments, non-current - option assignments, even \index{TeX}. +\meta{option} can be either a simple \meta{option name} or a \meta{relative node name}\texttt{.}\meta{option name}. The difference in the number of split values and given keys is handled gracefully. If there is not enough values, the superfluous keys are not processed; if there are too many values, the last key is called repeatedly. - For an example, see \S\ref{sec:example-decision-tree}. + The keys in \meta{keylist} can be any valid keys, including augmented assignments, non-current + option assignments, even \index{TeX} or user-defined styles. Actually, as |split| works by simply + appending |={|\meta{current value}|}| to the relevant given key, it is possible for the key to be + a (sub)keylist ending in a simple, non-valued key, like shown below. + + \begin{advise} + \item Pay attention to |%| characters around the subkeylist. In order for it to actually function + as a sublist, its braces should be stripped, but this can only happen if no spaces surround it. + \end{advise} + +\begin{forestexample}[point=split option,index={delay,content,split option,process args},label=ex:split option] + \begin{forest} + [ + {1,2,3,4} + [,delay={ + ~split option~= + {!parent.content} + {,} + { + content',% + {content+={+},content+}% + }, + tempcounta'/.process={O+n}{content}, + content+={=}, + content+/.register=tempcounta, + } + ] + ] + \end{forest} +\end{forestexample} \indexitem{node key>TeX}|=|\meta{toks: \TeX\ code} The given code is executed immediately. @@ -2771,14 +3030,14 @@ nodes; the existing nodes are not affected. \indexitem{node key>declare keylist}|=|\meta{option name}\meta{default value} Declares a \meta{keylist} option. - \indexitem{node key>declare dimen}|=|\meta{option name}\meta{pgfmath: default value} - Declares a \meta{dimen} option. + \indexitem{node key>declare dimen}|=|\meta{option name}\meta{default value} + Declares a \meta{dimen} option. The default value is processed by \index{forestmath}. - \indexitem{node key>declare count}|=|\meta{option name}\meta{pgfmath: default value} - Declares a \meta{count} option. + \indexitem{node key>declare count}|=|\meta{option name}\meta{default value} + Declares a \meta{count} option. The default value is processed by \index{forestmath}. - \indexitem{node key>declare boolean}|=|\meta{option name}\meta{pgfmath: default value} - Declares a \meta{boolean} option. + \indexitem{node key>declare boolean}|=|\meta{option name}\meta{default value} + Declares a \meta{boolean} option. The default value is processed by \index{forestmath}. \indexitem{node key>declare toks register}|=|\meta{register name} Declares a \meta{toks} register. @@ -2825,7 +3084,7 @@ The following options apply at stage \index{typeset nodes}. Changing them afterwards has no effect in the normal course of events. \begin{syntax} -\indexitem({{{{{}}}}}){option>align}|=|\index{value=align>left}\OR\index{value=align>center}\OR\index{value=align>right}\OR\meta{toks: tabular header} +\indexitem({{{{{}}}}}){option>align}|=|\index{value of=align>left}\OR\index{value of=align>center}\OR\index{value of=align>right}\OR\meta{toks: tabular header} Creates a left/center/right-aligned multiline node, or a tabular node. In the \index{content} option, the lines of the node should separated by |\\| and the columns (if @@ -2836,9 +3095,9 @@ afterwards has no effect in the normal course of events. \begin{forestexample}[index={l sep,align,base}] \begin{forest} l sep+=2ex [special value&actual value\\\hline - \indexdef{value=align>left}&||\texttt{@\{\}l@\{\}}\\ - \indexdef{value=align>center}&||\texttt{@\{\}c@\{\}}\\ - \indexdef{value=align>right}&||\texttt{@\{\}r@\{\}}\\ + \indexdef{value of=align>left}&||\texttt{@\{\}l@\{\}}\\ + \indexdef{value of=align>center}&||\texttt{@\{\}c@\{\}}\\ + \indexdef{value of=align>right}&||\texttt{@\{\}r@\{\}}\\ ,~align~=ll,draw [top base\\right aligned, ~align~=right,~base~=top] [left aligned\\bottom base, ~align~=left,~base~=bottom] @@ -2869,12 +3128,12 @@ afterwards has no effect in the normal course of events. This option controls the vertical alignment of multiline (and in general, \texttt{tabular}) nodes created with \index{align}. Its value becomes the optional argument to the \texttt{tabular} -environment. Thus, sensible values are \indexdef{value=base>t} (the top line of the table will -be the baseline) and \indexdef{value=base>b} (the bottom line of the table will be the baseline). +environment. Thus, sensible values are \indexdef{value of=base>t} (the top line of the table will +be the baseline) and \indexdef{value of=base>b} (the bottom line of the table will be the baseline). Note that this will only have effect if the node is anchored on a baseline, like in the default case of \index{option>anchor}|=base|. -For readability, you can use \indexdef{value=base>top} and \indexdef{value=base>bottom} instead +For readability, you can use \indexdef{value of=base>top} and \indexdef{value of=base>bottom} instead of \keyname{t} and \keyname{b}. (\keyname{top} and \keyname{bottom} are still stored as \keyname{t} and \keyname{b}.) @@ -2994,7 +3253,7 @@ given. \label{ref:ref-node-position} Most of the following options apply at stage \index{pack}. Changing them afterwards has no effect -in the normal course of events. (Options \index{option>l}, \index{option>s}, \index{x}, \index{y} and +in the normal course of events. (Options \index{option>l}, \index{option>s}, \index{option>x}, \index{y} and \index{option>anchor} are exceptions; see their documentation for details). \begin{syntax} @@ -3033,19 +3292,19 @@ in the normal course of events. (Options \index{option>l}, \index{option>s}, \i \let\outerleftmargin\leftmargin \begin{syntax} - \item\keyname{calign}|=|\indexdef{value=calign>child} s-aligns the node anchors of the parent and + \item\keyname{calign}|=|\indexdef{value of=calign>child} s-aligns the node anchors of the parent and the primary child. - \item\keyname{calign}|=|\indexdef{value=calign>child edge} s-aligns the parent anchor of the parent + \item\keyname{calign}|=|\indexdef{value of=calign>child edge} s-aligns the parent anchor of the parent and the child anchor of the primary child. - \item \keyname{calign}|=|\indexdef{value=calign>first} is an abbreviation for + \item \keyname{calign}|=|\indexdef{value of=calign>first} is an abbreviation for |calign=child,calign_child=1|. - \item \keyname{calign}|=|\indexdef{value=calign>last} is an abbreviation for + \item \keyname{calign}|=|\indexdef{value of=calign>last} is an abbreviation for |calign=child,calign_child=-1|. - \item\keyname{calign}|=|\indexdef{value=calign>midpoint} s-aligns the parent's node anchor and the + \item\keyname{calign}|=|\indexdef{value of=calign>midpoint} s-aligns the parent's node anchor and the midpoint between the primary and the secondary child's node anchor. - \item\keyname{calign}|=|\indexdef{value=calign>edge midpoint} s-aligns the parent's parent anchor + \item\keyname{calign}|=|\indexdef{value of=calign>edge midpoint} s-aligns the parent's parent anchor and the midpoint between the primary and the secondary child's child anchor. - \item \keyname{calign}|=|\indexdef{value=calign>center} is an abbreviation for\\ + \item \keyname{calign}|=|\indexdef{value of=calign>center} is an abbreviation for\\ |calign=midpoint,| |calign_primary_child=1,| |calign_secondary_child=-1|. \begin{forestexample} \begin{forest} @@ -3054,12 +3313,12 @@ in the normal course of events. (Options \index{option>l}, \index{option>s}, \i [last,calign=last[A][B][C]][8]] \end{forest} \end{forestexample} - \item\keyname{calign}|=|\indexdef{value=calign>fixed angles}: The angle between the direction of + \item\keyname{calign}|=|\indexdef{value of=calign>fixed angles}: The angle between the direction of growth at the current node (specified by option \index{grow}) and the line through the node anchors of the parent and the primary/secondary child will equal the primary/secondary angle. To achieve this, the block of children might be spread or further distanced from the parent. - \item\keyname{calign}|=|\indexdef{value=calign>fixed edge angles}: The angle between the direction of + \item\keyname{calign}|=|\indexdef{value of=calign>fixed edge angles}: The angle between the direction of growth at the current node (specified by option \index{grow}) and the line through the parent's parent anchor and the primary/secondary child's child anchor will equal the primary/secondary angle. @@ -3124,9 +3383,9 @@ a previously named path in tikz}. \box\codebox} \begin{itemize} - \item\keyname{fit}|=|\indexdef{value=fit>tight}: an exact boundary of the node's subtree is computed, + \item\keyname{fit}|=|\indexdef{value of=fit>tight}: an exact boundary of the node's subtree is computed, resulting in a compactly packed tree. Below, the boundary of subtree L is drawn. -\begin{forestexample}[point={fit,tight},index={fit,{value=fit>tight},delay,for step,tree,option>name,content,pgfmath}] +\begin{forestexample}[point={fit,tight},index={fit,{value of=fit>tight},delay,for step,tree,option>name,content,pgfmath}] \begin{forest} delay={for tree={name/.pgfmath=content}} [root @@ -3141,9 +3400,9 @@ a previously named path in tikz}. \tikz@addmode{\pgfsyssoftpath@setcurrentpath#1}% \appto\tikz@preactions{\let\tikz@actions@path#1}% }}\makeatother -\item\keyname{fit}|=|\indexdef{value=fit>rectangle}: puts the node's subtree in a rectangle and effectively +\item\keyname{fit}|=|\indexdef{value of=fit>rectangle}: puts the node's subtree in a rectangle and effectively packs this rectangle; the resulting tree will usually be wider. -\begin{forestexample}[point={fit,rectangle},index={fit,{value=fit>rectangle},delay,for step,tree,option>name,content,pgfmath}] +\begin{forestexample}[point={fit,rectangle},index={fit,{value of=fit>rectangle},delay,for step,tree,option>name,content,pgfmath}] \begin{forest} delay={for tree={name/.pgfmath=content}} [root @@ -3154,9 +3413,9 @@ a previously named path in tikz}. ] \end{forest} \end{forestexample} -\item\keyname{fit}|=|\indexdef{value=fit>band}: puts the node's subtree in a rectangle of ``infinite +\item\keyname{fit}|=|\indexdef{value of=fit>band}: puts the node's subtree in a rectangle of ``infinite depth'': the space under the node and its descendants will be kept clear. -\begin{forestexample}[point={fit,band},index={fit,{value=fit>band},delay,for step,tree,option>name,content,pgfmath}] +\begin{forestexample}[point={fit,band},index={fit,{value of=fit>band},delay,for step,tree,option>name,content,pgfmath}] \begin{forest} delay={for tree={name/.pgfmath=content}} [root @@ -3439,9 +3698,9 @@ used in any \TikZ; code. \begin{forest} for tree={~parent anchor~=south,~child anchor~=north} [VP[V][DP]] - \path[fill=red] (.parent anchor) circle[radius=2pt] - (!1.child anchor) circle[radius=2pt] - (!2.child anchor) circle[radius=2pt]; + \path[fill=red] (.parent anchor) circle[radius=2pt]; + \path[fill=blue] (!1.child anchor) circle[radius=2pt] + (!2.child anchor) circle[radius=2pt]; \end{forest} \end{forestexample} @@ -3468,8 +3727,7 @@ The values of these options provide various information about the tree and its n value via a |pgfmath| expression. If the given alias clashes with an existing node name, |alias| will yield an error, while |alias'| - will silently rename the node with this name to its default (|node@|\meta{id}) value. Use an - empty argument to reset the node's name to its default value. + will silently rename the node with this name to its default value (|node@|\meta{id}). Aliases can be used as the \meta{forest node name} part of a relative node name and as the argument to the \index{step>name} step of a node walk. The latter includes the usage @@ -3501,7 +3759,7 @@ The values of these options provide various information about the tree and its n In |pgfmath| expressions, this option is accessible as |n__|. -\indexitem(node@\meta{id}){option>name}|=|\meta{toks} +\indexitem{option>name}|=|\meta{toks} \hfill \texttt{node@}\meta{id} \itemnosep \indexitem{node key>name'}|=|\meta{toks} Sets the name of the node. @@ -3587,11 +3845,12 @@ example, see how the boundaries in the discussion of \index{fit} were drawn. \indexitem({{{{{}}}}}){option>tikz}|=|\meta{toks: \TikZ; code} ``Decorations.'' - The code given as the value of this option will be included in the |tikzpicture| environment - used to draw the tree. The code given to various nodes is appended in a depth-first, - parent-first fashion. The code is included after all nodes of the tree have been drawn, so it - can refer to any node of the tree. Furthermore, relative node names can be used to refer to - nodes of the tree, see \S\ref{ref:relative-node-names}. + The code given as the value of this option will be included in the |tikzpicture| environment used + to draw the tree. By default, the code is included after all nodes of the tree have been drawn, + so it can refer to any node of the tree (furthermore, relative node names can be used to refer to + nodes of the tree, see \S\ref{ref:relative-node-names}) and the code given to various nodes is + appended in a depth-first, parent-first fashion. See \S\ref{sec:draw-tree} for details and + customization. By default, bracket parser's afterthoughts feed the value of this option. See \index{afterthought}. @@ -3610,10 +3869,11 @@ step'' means to change the current node. Thus, nodewalk |parent,_parent,_n=2| d which first steps to the parent of the \emph{origin} node, then to its grandparent and finally to the second child of the origin's grandparent. -The origin of the nodewalk depends on how the nodewalk is invoked. When used after the \index>{!} in a -relative node name (\S\ref{ref:relative-node-names}), the origin is the node with the name given -before \index>{!}; when invoked by a spatial propagator such as \index{for step=\index{nodewalk}} -(\S\ref{ref:spatial-propagators}), the origin is the current node. +The origin of the nodewalk depends on how the nodewalk is invoked. When used after the \index>{!} +in a relative node name (\S\ref{ref:relative-node-names}), the origin is the node with the name +given before \index>{!}; when invoked by a spatial propagator such as \index{for + step=\index{nodewalk}} (\S\ref{ref:spatial-propagators}), the origin is the current node; when +invoked within another (outer) nodewalk, the origin is the current node of the outer nodewalk. Formally, a \meta{nodewalk} is a list of |pgfkeys| key--value pairs. Steps in a nodewalk are thus separated by commas. However, \foRest; also recognizes \emph{short-form} steps, whose names consist @@ -3662,21 +3922,21 @@ Each nodewalk has an associated \emph{every-step keylist}: a keylist of node key from \index{path>forest} path, \foRest; would spend way too much time checking if a given node option is actually a short-form nodewalk. - If you need to execute nodewalk keys within the every-step keylist, use node key - \index{node key>Nodewalk}.} which get executed after each step of the nodewalk. The every-step -keylist of the current nodewalk is contained in register \index{register>every step} and can be -changed at any point during the nodewalk. Its value at the start of the nodewalk depends on how the -nodewalk was invoked. In most cases (e.g.\ \index{step>nodewalk} or prefix -\index{for step}-based spatial propagators), it is given explicitely as an argument to the key -that executes the nodewalk. However, see \index{step>Nodewalk} for information on how the -every-step keylist of an embedded nodewalk can interact with the every-step keylist of its parent -nodewalk. + If you need to execute nodewalk keys within the every-step keylist, use node key \index{node + key>Nodewalk}.} which get executed after each step of the nodewalk. The every-step keylist of +the current nodewalk is contained in register \index{register>every step} and can be changed at any +point during the nodewalk. Its value at the start of the nodewalk depends on how the nodewalk was +invoked. In most cases (e.g.\ \index{step>nodewalk} or prefix \index{for step}-based spatial +propagators), it is given explicitely as an argument to the key that executes the nodewalk. +However, see \index{step>Nodewalk} option \index{option of=Nodewalk>every step} for information on +how the every-step keylist of an embedded nodewalk can interact with the every-step keylist of its +parent nodewalk. Each nodewalk step can be either \emph{real} or \emph{fake}. Fake steps only change the current node. Real steps also trigger execution of the every-step keylist and update of history. Fake steps are sometimes useful as a ``computational tool''. They can be introduced explicitely using -\index{nodewalk key>fake}; some other keys (like some history nodewalk keys, \S\ref{ref:nodewalk-history}) -introduce fake steps implicitely. +\index{nodewalk key>fake}; some other keys (like several history nodewalk keys, +\S\ref{ref:nodewalk-history}) introduce fake steps implicitely. In some cases, the nodewalk might step ``out of the tree''. (Imagine using \index{step>parent} at the root of the tree, or \index{readonly option>n}|=42| at a node with less that 42 children.) Our official term will @@ -3686,20 +3946,204 @@ error. However, the full story is told by \index{nodewalk key>on invalid}. Nodewalks can be hard to follow, especially when designing styles. \FoRest; does its best to help. First, it logs the nodewalk stack in case of error. Second, if package option -\index{debug} is given, it logs every step made. +\index{debug}|=|\index{option of=debug>nodewalks} is given, it logs every step made. + + +\subsubsection{Invoking (embedded) nodewalks} +\label{ref:embedded-walks} + +There are many ways to invoke a nodewalk. For example, several keys, like \index{fit to}, and +aggregate functions (\S\ref{ref:aggregate-functions}) expect a \meta{nodewalk} argument. This +section lists keys which can be used to explicitely invoke a nodewalk. + +The keys in this section can be used not only as node keys (in fact, not all of them can be used +so), but also as nodewalk keys. The latter fact means that they can be used to introduce embedded +nodewalks, which (can) have its own every-step keylist, history and on-invalid mode; for details on +how these properties of outer and embedded nodewalk can interact, see \index{step>Nodewalk}. There +is no limit to the depth of nodewalks embedding (nodewalk within nodewalk within nodewalk \dots). + +An embedded nodewalk functions as a single, fake step of the outer nodewalk. Specifically, this +means that, while stepping through the embedded nodewalk, the every-step keylist of the outer +nodewalk is not executed. Furthermore, by default, modifying the every-step keylist of the inner +walk (by manipulating register \index{register>every step}) does not influence the outer nodewalk +(but see option \index{option of=Nodewalk>every step}). + +An embedded nodewalk does not count as a (real, every-step keyslist invoking) step of the outer +nodewalk. After it is finished, there are two options with respect to the new current node of the +outer nodewalk,\footnote{Even the outermost explicitly invoked nodewalks actually have the outer + nodewalk. It is ``static'' in the sense that no real step is ever made in it, but it has all the + nodewalk properties --- the current node, \index{register>every step} keylist register, \index{option + of=Nodewalk>history} and \index{option of=Nodewalk>on invalid} mode (error) --- which can + interact with the embedded nodewalk.} depending on whether the embedded nodewalk was invoked using +a variant of the key with or without the \index{for step} prefix (all keys in this section have the +\index{for step} variant). +\begin{itemize} +\item For keys \emph{without} the \index{for step} prefix, the current node of the outer nodewalk + changes, \emph{via a fake step}, to the final node visited by the embedded nodewalk. This holds + even if the final node was reached as a fake step and even if it is invalid + (\index{option>id}|=0|). The fake step in the outer nodewalk cannot be made real, not even by + \index{nodewalk key>real}: if you want to execute the every-step keylist of the outer nodewalk at + the finishing node of the embedded nodewalk, follow the latter by step \index{current}. +\item For keys \emph{with} the \index{for step} prefix, the current node of the outer nodewalk + remains unchanged. For this reason, the \index{for step}-prefixed keys are available as node keys + (we call them spatial propagators, \S\ref{ref:spatial-propagators}), while the steps without this + prefix are generally not, with the sole exception of \index{step>Nodewalk}, which I advise to use + carefully. +\end{itemize} + +All steps described in this section can be prefixed by \index{for step}. All of them, with or +without this prefix, are available as nodewalk keys. The list of keys from this section which are +available as node keys: \index{step>Nodewalk}, \index{for step=\index{step>Nodewalk}}, \index{for + step=\index{nodewalk}}; you will most often want to use the latter. + + +\begin{syntax} +\indexitem{step>Nodewalk}|=|\meta{keylist: config}\meta{nodewalk}\meta{keylist: every-step} + + Walks an \meta{nodewalk} starting at the current node. + + This is the most generic form of embedding a nodewalk. Unlike other keys described in this + subsection, it can also be used as a node key even without the \index{for step} prefix, but take + care as it will, in general, change the current node. + + The \meta{config} argument serves to specify the interaction between the outer and embedded + nodewalk. It can contain the following keys: + + \let\outerleftmargin\leftmargin + \begin{syntax} + \indexitem(independent){option of=Nodewalk>every step}|={|\alternative{independent,inherited,shared}|}| + \indexitem(shared){option of=Nodewalk>history}|={|\alternative{independent,inherited,shared}|}| + + The following table shows what happens to the every-step keylist and history depending on the + value of \keyname{every step} and \keyname{history}, respectively. State B is \meta{every-step} + for every step and empty for history. + + \begin{tabular}{l|ccc} + &\keyname{independent}&\keyname{inherited}&\keyname{shared}\\\hline + state of the outer nodewalk&A&A&A\\ + initial state of the inner nodewalk&B&A&A\\ + \dots\\ + final state of the inner nodewalk&C&C&C\\ + state of the outer nodewalk&A&A&C + \end{tabular} + \end{syntax} + + As shown in the table above, argument \meta{every-step} is used to initialize the + embedded nodewalk's every-step keylist when it is independent of the outer nodewalk. In other + cases, this argument is ignored (use |{}|). + + \begin{syntax} + \indexitem(inherited){option of=Nodewalk>on invalid}|={|\alternative{error,fake,error in real,last valid,inherited}|}| + + Like \index{nodewalk key>on invalid}, but local to this nodewalk. The additional alternative + \indexdef{value of=on invalid>inherited} (which is the default) means to retain the current + value, regardless of how it was set (by an outer nodewalk, explicit \index{nodewalk key>on + invalid}, or the package default, \index{value of=on invalid>error}). + \end{syntax} + + \begin{advise} + \item Use \index{node key>Nodewalk} if you need to execute nodewalk keys within the every-step + keylist. + \end{advise} + +\begin{forestexample}[index={register>every step}] + \begin{forest} + for 2=calign with current, for children={for descendants={circle,draw}} + [every step, + [independent,for nodewalk={ + 1,Nodewalk={~every step=independent~}{1,every step=fill,1}{},1 + }{draw=red}, + [[[[]]]]] + [inherited,for nodewalk={ + 1,Nodewalk={~every step=inherited~}{1,every step=fill,1}{},1 + }{draw=red}, + [[[[]]]]] + [shared,for nodewalk={ + 1,Nodewalk={~every step=shared~}{1,every step=fill,1}{},1 + }{draw=red}, + [[[[]]]]]] + \end{forest} +\end{forestexample} + + +\begin{forestexample}[index={history,walk back}] + \begin{forest} + mark/.style={tempcounta+=1,content+/.register=tempcounta,content+={,}}, + [history:\\effect on the,align=center + [inner nodewalk + % uncommenting this would result in an error: + % [independent, delay={for nodewalk={ + % tempcounta=0,111, + % Nodewalk={history=independent}{walk back=2}{mark,fill=yellow} + % }{mark,draw=red}}, + % [[[]]]] + [inherited\\or\\shared, align=center,delay={for nodewalk={ + tempcounta=0,111, + Nodewalk={~history=inherited~}{walk back=2}{mark,fill=yellow} + }{mark,draw=red}}, + [[[]]]]] + [outer nodewalk + [inherited,delay={for nodewalk={ + tempcounta=0,111, + Nodewalk={~history=inherited~}{11}{mark,fill=yellow}, + walk back=2 + }{mark,draw=red}}, + [[[[[]]]]]] + [shared,delay={for nodewalk={ + tempcounta=0,111, + Nodewalk={~history=shared~}{11}{mark,fill=yellow}, + walk back=2 + }{mark,draw=red}}, + [[[[[]]]]]]]] + \end{forest} +\end{forestexample} + +\indexitem{step>nodewalk}|=|\meta{nodewalk}\meta{keylist: every-step} + + This key is a shorthand for + + \begin{center} + \index{step>Nodewalk}|={|\index{option of=Nodewalk>every step}|=independent,|\index{option + of=Nodewalk>history}|=independent,|\index{option of=Nodewalk>on + invalid}|=inherited}|\meta{nodewalk}\meta{keylist: every-step} + \end{center} + + \begin{advise} + \item \index{for step=\index{nodewalk}} is the most common way to explicitely invoke a nodewalk from a + node keylist (the keylist immediately following the content of the node). + \end{advise} + +\indexitem{step>nodewalk'}|=|\meta{nodewalk} + + This key is a shorthand for + + \begin{center} + \index{step>Nodewalk}|={|\index{option of=Nodewalk>every step}|=inherited,|\index{option + of=Nodewalk>history}|=independent,|\index{option of=Nodewalk>on + invalid}|=inherited}|\meta{nodewalk}|{}| + \end{center} + + \begin{advise} + \item Using this key, it is easy to ``\emph{temporarily} change'' the \index{register>every step} + keylist of a nodewalk. + \item Using \index{for step=\index{nodewalk'}} is probably the easiest way to make a ``trip'' + within a nodewalk, i.e.\ walk some steps but return to their origin afterwards. + \item This key (with or without the \index{for step} prefix) is not available as a node key --- it + would make little sense there, as it has no every-step keylist argument. + \end{advise} + +\end{syntax} \subsubsection{Single-step keys} \label{ref:single-step-keys} -Single-step nodewalk keys visit a single node. If the node a single-step is trying to visit does -not exist, the current node is set to the invalid node (i.e.\ node with \index{readonly option>id}|=0|). This -can be useful for looping, see \S\ref{ref:loops}. Use \index{last valid} or \index{last valid'} -to return to the node that was current before the ``unsuccessful'' single-step. +Single-step nodewalk keys visit a single node. The behaviour in the situation when the target node +does not exist is determined by \index{nodewalk key>on invalid}. -For each single-step key, propagator \index{for step=\meta{step}} is also defined. +For each single-step key, spatial propagator \index{for step=\meta{step}} is also defined. \index{for step=\meta{step}}|=|\meta{keylist} is equivalent to -\index{propagator>for}|={|\meta{step}|}{|\meta{keylist}|}|. If the step takes an argument, then its +\index{for step=\index{nodewalk}}|={|\meta{step}|}{|\meta{keylist}|}|. If the step takes an argument, then its \index{for step=\meta{step}} propagator takes two and the argument of the step precedes the \meta{keylist}. See also \S\ref{ref:spatial-propagators}. @@ -3851,6 +4295,16 @@ parent-first first-child-first. the children within each level, but the levels are still traversed from the highest to the deepest. +\indexitem{step>leaves} + + Visits all the leaves in the current node's subtree. + +\indexitem[index key={level-}]{step>-level}|=|\meta{count} +\itemnosep +\indexitem[index key={level-'}]{step>-level'}|=|\meta{count} + +Visits all the nodes \meta{count} levels above the leaves in the current node's subtree. + \indexitem[+print form=\spaces{12},print form+=\spaces{9}]{step>preceding siblings}\quad\quad \indexdef[+print form=\spaces{12}]{step>following siblings}% \itemnosep @@ -3890,199 +4344,111 @@ Visit all preceding or following nodes of the entire tree, in the linear order; \end{syntax} -\subsubsection{Embedded nodewalks} -\label{ref:embedded-walks} -An embedded nodewalk is a nodewalk within a nodewalk. The embedded nodewalk has its own every-step -keylist. While stepping through the inner nodewalk, the every-step keylist of the outer nodewalk is -not executed. Modifying the every-step keylist of the inner walk (by \index{register>every step}) does not -influence the outer nodewalk. +\subsubsection{Operations} +\label{ref:nodewalk-operations} -After the embedded nodewalk finished, its final current node becomes the current node of the outer -nodewalk. This is true even if the final node was reached by a fake step. +Generally speaking, nodewalk operations take an \emph{input nodewalk} and transform it into +an \emph{output nodewalk}, while possibly also having side effects. -\begin{advise} -\item As node keys can be used within nodewalks, one can use spatial propagators - (\S\ref{ref:spatial-propagators}) like \index{for step=\index{step>nodewalk}} to embed a nodewalk - which (silently) returns to the current node of the outer nodewalk. -\end{advise} +The most important categorization of operations is in terms of the input nodewalk: +\begin{itemize} +\item ``Normal'' keys execute the input nodewalk ``invisibly'', i.e.\ with a every-step keylist that + is initially empty. However, even such an ``invisible'' nodewalk might not always be completely + without effect. For example, the effects of any node keys contained in the input nodewalk or + modifications of its (initially empty) every-step keylist will be felt. +\item Most of the operation keys have the |walk_and_...| variant, where input given nodewalk is meant to + be ``visible'': it is walked directly in the context of the invoking nodewalk (specifically, with + its every-step keylist in effect). +\item Some operation keys have the |..._in_nodewalk| variant, which operates on the portion of the + current nodewalk that was already walked. +\item \index{load} has no input nodewalk. +\end{itemize} +All operation keys except |..._in_nodewalk| variants can be prefixed by \index{for step} to create a +spatial propagator (\S\ref{ref:spatial-propagators}). -An embedded nodewalk does not count as a step of the outer nodewalk (except if noted otherwise, see -\index{group}). This means that the every-step keylist of the outer nodewalk is not executed at -the final node of the embedded nodewalk. In other words, the step made by the embedded nodewalk as -a unit is fake. +The output nodewalk is always walked in the context of the invoking nodewalk. However, note that, +as mentioned above, in the case of |walk_and_...| variants, that context can be changed during the +execution of the input nodewalk. -Embedded nodewalks also have their own origin and history. Nodewalks can be nested to an arbitrary -level. +Trivia: \index{save} is the only operation with no output nodewalk and also the only operation with +a ``side effect'' (of saving the nodewalk, obviously). +For some operations (\index{filter} and \index{branch}), the every-step keylist contains instructions +on how collect the relevant information. While you can safely append and prepend to +\index{register>every step} keylist of their input nodewalk, you should not completely rewrite +it. If you want the operations to actually work, of course. + \begin{syntax} -\indexitem{step>Nodewalk}|=|\meta{keylist: config}\meta{nodewalk}\meta{keylist: every-step} - - Walks an (embedded) \meta{nodewalk} starting at the current node. - - From the perspective of the outer nodewalk, the embedded nodewalk is an (implicitely) fake step - (and cannot be made real by \index{real}): the last node visited by the embedded - \meta{nodewalk} becomes the new current node of the outer nodewalk, even if it is invalid. - - The \meta{config} argument serves to specify the interaction between the outer and embedded - nodewalk. It can contain the following keys: - - \let\outerleftmargin\leftmargin - \begin{syntax} - \indexitem(independent){option of=Nodewalk>every step}|={|\alternative{independent,inherited,shared}|}| - \indexitem(shared){option of=Nodewalk>history}|={|\alternative{independent,inherited,shared}|}| +\indexitem{step>group}|=|\meta{nodewalk} - The following table shows what happens to the every-step keylist and history depending on the - value of \keyname{every step} and \keyname{history}, respectively. State B is \meta{every-step} - for every step and empty for history. - - \begin{tabular}{l|ccc} - &\keyname{independent}&\keyname{inherited}&\keyname{shared}\\\hline - state of the outer nodewalk&A&A&A\\ - initial state of the inner nodewalk&B&A&A\\ - \dots\\ - final state of the inner nodewalk&C&C&C\\ - state of the outer nodewalk&A&A&C - \end{tabular} - \end{syntax} + Treat \meta{nodewalk} as a single step of the (outer) nodewalk, i.e.\ the outer every-step keylist + is executed only at the end of the embedded nodewalk. The embedded \meta{nodewalk} inherits + history from the outer nodewalk. Using this key is equivalent to writing + \begin{center} + \index{step>Nodewalk}|={|\index{option of=Nodewalk>every step}|=independent,|\index{option + of=Nodewalk>history}|=inherited}|\meta{nodewalk}|{}, current| + \end{center} - As shown in the table above, argument \meta{every-step} is used to initialize the - embedded nodewalk's every-step keylist when it is independent of the outer nodewalk. In other - cases, this argument is ignored (use |{}|). + + \indexitem{step>reverse}|=|\meta{nodewalk} + \itemnosep + \indexitem{step>walk and reverse}|=|\meta{nodewalk} - \begin{syntax} - \indexitem(inherited){option of=Nodewalk>on invalid}|={|\alternative{error,fake,step,inherited}|}| + Visits the nodes of the given \meta{nodewalk} in the reversed order. - Like \index{nodewalk key>on invalid}, but local to this nodewalk. The additional alternative - \indexdef{value=on invalid>inherited} (which is the default) means to behave as specified by - \index{nodewalk key>on invalid} (or the package default, \index{value=on invalid>error}, if no - \index{nodewalk key>on invalid} was given). - \end{syntax} + \indexitem{step>unique}|=|\meta{nodewalk} -\begin{forestexample} - \begin{forest} - for 2=calign with current, for children={for descendants={circle,draw}} - [every step, - [independent,for nodewalk={ - 1,Nodewalk={~every step=independent~}{1,every step=fill,1}{},1}{draw=red}, - [[[[]]]]] - [inherited,for nodewalk={ - 1,Nodewalk={~every step=inherited~}{1,every step=fill,1}{},1}{draw=red}, - [[[[]]]]] - [shared,for nodewalk={ - 1,Nodewalk={~every step=shared~}{1,every step=fill,1}{},1}{draw=red}, - [[[[]]]]]] - \end{forest} -\end{forestexample} + Walks the \meta{nodewalk}, but visits each node at most once. - -\begin{forestexample} - \begin{forest} - mark/.style={tempcounta+=1,content+/.register=tempcounta,content+={,}}, - [history:\\effect on the,align=center - [inner nodewalk - % uncommenting this would result in an error: - % [independent, delay={for nodewalk={ - % tempcounta=0,111, - % Nodewalk={history=independent}{walk back=2}{mark,fill=yellow} - % }{mark,draw=red}}, - % [[[]]]] - [inherited\\or\\shared, align=center,delay={for nodewalk={ - tempcounta=0,111, - Nodewalk={~history=inherited~}{walk back=2}{mark,fill=yellow} - }{mark,draw=red}}, - [[[]]]]] - [outer nodewalk - [inherited,delay={for nodewalk={ - tempcounta=0,111, - Nodewalk={~history=inherited~}{11}{mark,fill=yellow}, - walk back=2 - }{mark,draw=red}}, - [[[[[]]]]]] - [shared,delay={for nodewalk={ - tempcounta=0,111, - Nodewalk={~history=shared~}{11}{mark,fill=yellow}, - walk back=2 - }{mark,draw=red}}, - [[[[[]]]]]]]] - \end{forest} -\end{forestexample} - -\indexitem{step>nodewalk}|=|\meta{nodewalk}\meta{keylist: every-step} - - This key is a shorthand for +\indexitem{step>filter}|=|\meta{nodewalk}\index{forestmath=condition} - \begin{center} - \index{step>Nodewalk}|={|\index{option of=Nodewalk>every step}|=independent,|\index{option of=Nodewalk>history}|=independent}|\meta{nodewalk}\meta{keylist: every-step} - \end{center} +Visit the nodes of the given \meta{nodewalk} for which the given \meta{condition} is true. \begin{advise} - \item \index{for step=\index{nodewalk}} is also defined. + \item You can safely append and prepend to \index{register>every step} keylist during the input + \meta{nodewalk}, but you should not completely rewrite it. \end{advise} - -\indexitem{step>nodewalk'}|=|\meta{nodewalk} - This key is a shorthand for - \begin{center} - \index{step>Nodewalk}|={|\index{option of=Nodewalk>every step}|=inherited,|\index{option of=Nodewalk>history}|=independent}|\meta{nodewalk}\meta{keylist: every-step} - \end{center} - - \begin{advise} - \item \index{for step=\index{nodewalk'}} is also defined. - \end{advise} - -\indexitem{step>group}|=|\meta{nodewalk} +\indexitem{step>branch}|={|\meta{nodewalk$_1$}|,...,|\meta{nodewalk$_n$}|}| + \itemnosep +\indexitem{step>branch'}|={|\meta{nodewalk$_1$}|,...,|\meta{nodewalk$_n$}|}| - Treat \meta{nodewalk} as a single step of the (outer) nodewalk, i.e.\ the outer every-step keylist - is executed only at the end of the embedded nodewalk. The embedded \meta{nodewalk} inherits - history from the outer nodewalk. Using this key is equivalent to writing - \begin{center} - \index{step>Nodewalk}|={|\index{option of=Nodewalk>every step}|=independent,|\index{option - of=Nodewalk>history}|=inherited}|\meta{nodewalk}|{}, current| - \end{center} +Visit the nodes in a ``cartesian product'' of any number of nodewalks, where a cartesian product is +defined as a nodewalk where at every step of \meta{nodewalk$_i$} ($1\leq i<n$), +\meta{nodewalk$_{i+1}$} is executed. - \begin{advise} - \item It is safe to modify the every-step keylist of \meta{nodewalk}. - \item \index{for step=\index{group}} is also defined. - \end{advise} - - -\end{syntax} +The |branch| variant visits only the nodes visited by the innermost nodewalk, \meta{nodewalk$_n$}. +The |branch'| variant visits the nodes visited by all the nodewalks of the product, +\meta{nodewalk$_1$} \dots\ \meta{nodewalk$_n$}. -\subsubsection{Operations} -\label{ref:nodewalk-operations} +For an example of each, see \index{c-commanded} and \index{c-commanders} from the +\reflibrary{linguistics} library. -Operations internally walk the given nodewalk (except |..._in_nodewalk| variants, which operate on -the portion of the current nodewalk that was already walked) to gather some information about -visited nodes. Then, based on that information, they walk some steps in the context (most -importantly, with \index{register>every step} keylist) of the current nodewalk. + \begin{advise} + \item You can safely append and prepend to \index{register>every step} keylists during the input + \meta{nodewalk}s, but you should not completely rewrite them. + \end{advise} -Most of the following keys have a |walk_and_...| variant, which first walks the given nodewalk and -then performs the desired operation. All operation keys except |..._in_nodewalk| variants can be -prefixed by \index{for step}. -\begin{advise} -\item The every-step keylist of the internal nodewalk is empty; or, more precisely, it contains only - instructions to how collect the relevant information. You can safely append and prepend to - \index{register>every step} keylist of the internal nodewalk, but you should not completely - rewrite it. -\end{advise} - -\begin{syntax} - \indexitem{step>reverse}|=|\meta{nodewalk} + \indexitem{step>save}|=|\meta{toks: name}\meta{nodewalk} \itemnosep - \indexitem{step>walk and reverse}|=|\meta{nodewalk} + \indexitem{step>walk and save}|=|\meta{toks: name}\meta{nodewalk} - Visits the nodes of the given \meta{nodewalk} in the reversed order. + Saves the given \meta{nodewalk} under the given name. - \indexitem{nodewalk key>save}|=|\meta{toks: name}\meta{nodewalk} + \indexitem{step>save append}|=|\meta{toks: name}\meta{nodewalk} \itemnosep - \indexitem{step>walk and save}|=|\meta{toks: name}\meta{nodewalk} + \indexitem{step>save prepend}|=|\meta{toks: name}\meta{nodewalk} + \itemnosep + \indexitem{step>walk and save append}|=|\meta{toks: name}\meta{nodewalk} + \itemnosep + \indexitem{step>walk and save prepend}|=|\meta{toks: name}\meta{nodewalk} - Saves the given \meta{nodewalk} under the given name. + Appends/prepends the given \meta{nodewalk} to nodewalk \meta{name}. \indexitem{step>load}|=|\meta{toks: name} Walks the nodewalk saved under the given name. @@ -4090,6 +4456,7 @@ prefixed by \index{for step}. a different current node, or even with a tree whose geometry has changed (see \S\ref{ref:dynamic}) will still visit exactly the nodes that were visited when the nodewalk was saved. + \indexitem{step>sort}|=|\meta{nodewalk} \itemnosep \indexitem{step>sort'}|=|\meta{nodewalk} @@ -4103,7 +4470,7 @@ prefixed by \index{for step}. the descending order. The \keyname{walk and sort} variants first visit the nodes in the order specified by the given \meta{nodewalk}. - \indexitem{node key>sort by}|={|\meta{pgfmath}|,|\dots|,|\meta{pgfmath}|}| + \indexitem{node key>sort by}|={|\index{forestmath}|,|\dots|,|\index{forestmath}|}| Sets the sorting order used by all keys comparing nodes: \index{step>sort}, \index{step>min} and \index{step>max} key families in the nodewalk namespace, and the \index{dynamic @@ -4117,13 +4484,43 @@ prefixed by \index{for step}. Simply put, if you want to sort first by the number of children and then by content, say |sort_by={|\index[+print format=pgfmath]{n children}|,_|\index{content}|}|. - In the simplest case, the given \meta{pgfmath} expressions are simply node options. However, as + In the simplest case, the given \index{forestmath} expressions are simply node options. However, as any |pgfmath| expression is allowed in the sort key, you can easily sort by the product of the content of the current node and the content of its first child: - |sort_by={|\index{content}|()*|\index{content}|("|\index>{!}|1")|. Note, however, that the value returned by these expression - must be numeric, i.e.\ alphabetic comparison of strings is not implemented. + |sort_by={|\index{content}|()*|\index{content}|("|\index>{!}|1")|. + To sort alphabetically, one must use the argument processor (\S\ref{ref:argument-processor}) to + specify the sort order. In particular, the key must be marked as text using \index{processor>t}. + The first example below shows a simple alphabetical sort by content; the second sorts the + filenames by suffix first (in the ascending order) and then by the basename (in the descending + order, see \index{processor>-}). + +\begin{forestexample} + \begin{forest} + [,phantom,grow'=0,for children={anchor=west,child anchor=west},s sep=0, + delay={~sort by=>O+t{content},sort~} + [example.tex][example.pdf][example.log][example.aux] + [thesis.tex][thesis.pdf][thesis.log][thesis.aux][thesis.toc] + ] + \end{forest} +\end{forestexample} +\begin{forestexample} + \begin{forest} + declare toks={basename}{}, + declare toks={extension}{}, + [,phantom,grow'=0,for children={anchor=east},s sep=0, + delay={ + for children={split option={content}{.}{basename,extension}}, + ~sort by={>O+t{extension},>O+t-{basename}}~, + ~sort~, + } + [example.tex][example.pdf][example.log][example.aux] + [thesis.tex][thesis.pdf][thesis.log][thesis.aux][thesis.toc] + ] + \end{forest} +\end{forestexample} + \indexitem{step>min}|=|\meta{nodewalk}, \indexdef{step>max}|=|\meta{nodewalk} \itemnosep \indexitem{step>walk and min}|=|\meta{nodewalk}, \indexdef{step>walk and max}|=|\meta{nodewalk} @@ -4154,26 +4551,6 @@ prefixed by \index{for step}. node by moving back in the history, see \index{back}. -\indexitem{step>filter}|=|\meta{nodewalk}\meta{pgfmath: condition} - -Visit the nodes of the given \meta{nodewalk} for which the given \meta{condition} is true. - - -\indexitem{step>branch}|={|\meta{nodewalk$_1$}|,...,|\meta{nodewalk$_n$}|}| - \itemnosep -\indexitem{step>branch'}|={|\meta{nodewalk$_1$}|,...,|\meta{nodewalk$_n$}|}| - -Visit the nodes in a ``cartesian product'' of any number of nodewalks, where a cartesian product is -defined as a nodewalk where at every step of \meta{nodewalk$_i$} ($1\leq i<n$), -\meta{nodewalk$_{i+1}$} is executed. - -The |branch| variant visits only the nodes visited by the innermost nodewalk, \meta{nodewalk$_n$}. -The |branch'| variant visits the nodes visited by all the nodewalks of the product, -\meta{nodewalk$_1$} \dots\ \meta{nodewalk$_n$}. - -For an example of each, see \index{c-commanded} and \index{c-commanders} from the -\reflibrary{linguistics} library. - \end{syntax} \subsubsection{History} @@ -4254,7 +4631,7 @@ current nodewalk. The variant \emph{without} |'| makes a fake step. More precisely, it behaves as if both \index{nodewalk key>fake} and \index{nodewalk key>on invalid}|=fake| are in effect. -\indexitem(error){nodewalk key>on invalid}|={|\alternative{error,fake,step}|}|\meta{nodewalk} +\indexitem{nodewalk key>on invalid}|={|\alternative{error,fake,step}|}|\meta{nodewalk} This key determines what should happen if a nodewalk step landed on the invalid node, i.e.\ the node with \index{readonly option>id}|=0|. @@ -4265,15 +4642,19 @@ current nodewalk. \let\outerleftmargin\leftmargin \begin{syntax} - \item |on invalid=|\indexdef{value=on invalid>error} produces an error; - \item |on invalid=|\indexdef{value=on invalid>fake} does nothing: history is not updated and the - every-step keylist is not executed, thus making the step essentialy fake; - \item |on invalid=|\indexdef{value=on invalid>step} makes a step, either real or fake, depending - on the environment. + \item |on invalid={|\indexdef{value of=on invalid>error}|}|\meta{nodewalk} produces an error; + \item |on invalid={|\indexdef{value of=on invalid>fake}|}|\meta{nodewalk} does nothing: history is + not updated and the every-step keylist is not executed, thus making the step essentialy fake; + \item |on invalid={|\indexdef{value of=on invalid>error if real}|}|\meta{nodewalk} produces an + error unless \index{nodewalk key>fake} is in effect. + \item |on invalid={|\indexdef{value of=on invalid>last valid}|}|\meta{nodewalk} returns to the + last valid node, by making a fake step, like \index{step>last valid}. \end{syntax} Loops with the implicit |id=0| condition (\S\ref{ref:loops}) automatically switch to |on_invalid=fake| mode. + + See also \index{step>Nodewalk} option \index{option of=Nodewalk>on invalid}. \indexitem{nodewalk key>options}=\meta{keylist: node keys} @@ -4317,7 +4698,7 @@ commas. Here's the list of predefined short steps and their corresponding long- \indexitem{short step>R} the formal root node --- \index{root'} \indexitem{short step>b} back one fake step in history --- \index{back}|=1| \indexitem{short step>f} forward one fake step in history --- \index{forward}|=1| -\indexitem{short step>v} last valid node in the current nodewalk, fake version --- \index{last valid} +\indexitem{short step>v} last valid node in the current nodewalk, fake version --- \index{step>last valid} \indexitem{short step>*}\meta{count: n}\meta{keylist} repeat keylist $n$ times --- \index{repeat}|=|\meta{count: n}\meta{keylist} \item {\rstyle $\{$}\meta{keylist}{\rstyle $\}$} put keylist in a group --- \index{group}|=|\meta{keylist} \end{syntax} @@ -4342,10 +4723,10 @@ redefining short steps is always ok, however, as they are never used in the code Should we make a \index{for step} prefix for the step? \item\indexdef{option of=define long step>strip fake steps}|=|\meta{boolean}\hfill |true| - Imagine that \meta{nodewalk} ends with fake steps. Now, fake steps are usually just a computational tool, so we normally wouldn't want the current node after the walk to be one of them. As far as the outer world is concerned, we want the node to end at the last real step. However, simply appending \index{last valid} to our style will not work. Imagine that the nodewalk results in no steps. In this case, we'd want to remain at the origin of our empty nodewalk. However, imagine further that the (outer) step just before the empty nodewalk was fake. Then \index{last valid} will not step to the correct node: instead of staying at the origin, it will go to the node that the last real step prior to our nodewalk stepped to. In case there was no such real step, we'd even step to the invalid node (normally getting an error). + Imagine that \meta{nodewalk} ends with fake steps. Now, fake steps are usually just a computational tool, so we normally wouldn't want the current node after the walk to be one of them. As far as the outer world is concerned, we want the node to end at the last real step. However, simply appending \index{step>last valid} to our style will not work. Imagine that the nodewalk results in no steps. In this case, we'd want to remain at the origin of our empty nodewalk. However, imagine further that the (outer) step just before the empty nodewalk was fake. Then \index{step>last valid} will not step to the correct node: instead of staying at the origin, it will go to the node that the last real step prior to our nodewalk stepped to. In case there was no such real step, we'd even step to the invalid node (normally getting an error). Defining the step using |strip fake steps| ensures the correct behaviour described - above. Set |strip fake steps=false| only when the fake steps at the end of the nodewalk at + above. Set |strip fake steps=false| only when the fake steps at the end of the nodewalk are important to you. \begin{advise} @@ -4375,45 +4756,64 @@ To (re)define braces, |{}|, write |define short step={group}{1}{...}|. \indexitem{handler>nodewalk style}|=|\meta{nodewalk} -A shorthand for |for nodewalk={|\meta{nodewalk}|}{}|. +\meta{nodewalk key}|/.nodewalk style=|\meta{nodewalk} is a shorthand for\\ +|for_nodewalk={|\meta{nodewalk key}|/.style=|\meta{nodewalk}|}{}|. \end{syntax} -\subsection{Conditionals and loops} +\subsection{Conditionals} \label{ref:conditionals} -\label{ref:loops} - -All conditionals take arguments \meta{true keylist} and \meta{false keylist}, and all loops take an -argument \meta{keylist}. The interpretation of the keys in these keylists depends on the -environment the conditional/loop appears in. If it is a part of a nodewalk -specification, the keys are taken to be nodewalk keys (\S\ref{ref:nodewalks}), otherwise node keys -(\S\ref{ref:node-keys}). -All the loops and conditionals can be nested safely. +All conditionals take arguments \meta{true keylist} and \meta{false keylist}. The interpretation of +the keys in these keylists depends on the environment the conditional appears in. If it is a part +of a nodewalk specification, the keys are taken to be nodewalk keys (\S\ref{ref:nodewalks}), +otherwise node keys (\S\ref{ref:node-keys}). -\begin{advise} -\item Except in special circumstances, you probably don't want to embed keys from the \index{where - option} family within a \index{for step=\index{tree}}, as this results in two nested loops. It - is more usual to use an \index{conditional>if} family key there. For an example where using - \index{where option} actually does the wrong thing, see question - \href{http://tex.stackexchange.com/questions/167978/smaller-roofs-for-forest}{Smaller roofs for - forest} on \TeX\ Stackexchange. -\end{advise} +All the conditionals can be nested safely. \begin{syntax} -\indexitem{conditional>if}|=|\meta{pgfmath condition}\meta{true keylist}\meta{false keylist} +\indexitem{conditional>if}|=|\index{forestmath=condition}\meta{true keylist}\meta{false keylist} - If \meta{pgfmath condition} evaluates to |true| (non-zero), \meta{true keylist} is processed (in + If \index{forestmath=condition} evaluates to |true| (non-zero), \meta{true keylist} is processed (in the context of the current node); otherwise, \meta{false keylist} is processed. For a detailed description of |pgfmath| expressions, see \cite[part VI]{tikzpgf2.10}. (In short: write the usual mathematical expressions.) + In the following example, \index{conditional>if} is used to orient the arrows from the smaller + number to the greater, and to color the odd and even numbers differently. (Style |random_tree| is + defined in the front page example.) + +\forestset{random tree/.style n args={3}{% #1=max levels, #2=max children, #3=max content + content/.pgfmath={random(0,#3)}, + if={#1>0}{repeat={random(0,#2)}{append={[,random tree={#1-1}{#2}{#3}]}}}{}}} +\begin{forestexample}[index={before typesetting nodes,for step,descendants,conditional>if,content,edge,edge label,tree},index>={!},point=if] + \pgfmathsetseed{314159} + \begin{forest} + before typesetting nodes={ + for descendants={ + if={content()>content("!u")}{edge=->}{ + if={content()<content("!u")}{edge=<-}{}}, + edge label/.wrap pgfmath arg= + {node[midway,above,sloped,font=\scriptsize]{+#1}} + {int(abs(content()-content("!u")))} + }, + for tree={circle,if={mod(content(),2)==0} + {fill=yellow}{fill=green}} + } + [,random tree={3}{3}{100}] + \end{forest} +\end{forestexample} + + + + \indexitem{word prefix=option>conditional>if=\meta{option}}|=|\meta{value}\meta{true keylist}\meta{false keylist} - A simple conditional is defined for every \meta{option}: if \meta{value} equals the value of the - option at the current node, \meta{true keylist} is executed; otherwise, \meta{false keylist}. +This simple conditional is defined for every \meta{option} (except boolean options, see below): if +\meta{value} equals the value of the option at the current node, \meta{true keylist} is executed; +otherwise, \meta{false keylist}. \indexitem{word prefix=boolean option>conditional>if=\meta{boolean option}}|=|\meta{true keylist}\meta{false keylist} @@ -4427,7 +4827,33 @@ All the loops and conditionals can be nested safely. otherwise \meta{false keylist}. This conditional is defined only for \meta{toks} options, see \S\ref{sec:option-setting}. + + +\indexitem[set={ + index format={result=if \protect\meta{dimen option}\protect\greaterthan,pgfkey}, + print format={result/.option=argument,+result={if\ },result+={>}, pgfkey}, +}]{conditional>if dimen GT=\protect\meta{dimen option}}|=|\meta{value}\meta{true keylist}\meta{false keylist} +\itemnosep +\indexitem[set={ + index format={result=if \protect\meta{dimen option}<,pgfkey}, + print format={result/.option=argument,+result={if\ },result+={<}, pgfkey}, +}]{conditional>if dimen LT=\protect\meta{dimen option}}|=|\meta{value}\meta{true keylist}\meta{false keylist} +\itemnosep +\indexitem[set={ + index format={result=if \protect\meta{count option}\protect\greaterthan,pgfkey}, + print format={result/.option=argument,+result={if\ },result+={>}, pgfkey}, +}]{conditional>if count GT=\protect\meta{count option}}|=|\meta{value}\meta{true keylist}\meta{false keylist} +\itemnosep +\indexitem[set={ + index format={result=if \protect\meta{count option}<,pgfkey}, + print format={result/.option=argument,+result={if\ },result+={<}, pgfkey}, +}]{conditional>if count LT=\protect\meta{count option}}|=|\meta{value}\meta{true keylist}\meta{false keylist} + +If the current value of the dimen/count option is greater/less than or equal to \meta{value}, +execute \meta{true keylist}; else, execute \meta{false keylist}. + + \indexitem{conditional>if nodewalk valid}|=|\meta{keylist: test nodewalk}\meta{true keylist}\meta{false keylist} If the test nodewalk finished on a valid node, \meta{true keylist} is processed (in the context of @@ -4438,7 +4864,12 @@ All the loops and conditionals can be nested safely. If the test nodewalk contains no (real) steps, \meta{true keylist} is processed (in the context of the current node); otherwise, \meta{false keylist} is processed. -\indexitem{conditional>if in saved nodewalk}|=|\meta{nodewalk}\meta{toks: nodewalk name}\meta{true keylist}\meta{false keylist} +\indexitem{conditional>if current nodewalk empty}|=|\meta{true keylist}\meta{false keylist} + + If the current nodewalk contains no (real) steps, \meta{true keylist} is processed (in the context of + the current node); otherwise, \meta{false keylist} is processed. + + \indexitem{conditional>if in saved nodewalk}|=|\meta{nodewalk}\meta{toks: nodewalk name}\meta{true keylist}\meta{false keylist} If the node at the end of \meta{nodewalk} occurs in the saved nodewalk, \meta{true keylist} is processed (in the context of the current node); otherwise, \meta{false keylist} is processed. @@ -4455,37 +4886,89 @@ processed (in the context of the current node); otherwise, \meta{false keylist} \indexitem{propagator>if have delayed'}|=|\meta{nodewalk}\meta{true keylist}\meta{false keylist} Like \index{if have delayed}, but assume the processing order given by \meta{nodewalk}. +\end{syntax} + + + +The following keys are shortcuts: they execute their corresponding |if ...| conditional for every +node in the subtree of the current node (including the node itself). In other words: + +\begin{center} + |where ...|\meta{arg$_1$}\dots\meta{arg$_n$}|/.style={for tree={if ...=|\meta{arg$_1$}\dots\meta{arg$_n$}|}}| +\end{center} + +\begin{advise} +\item Except in special circumstances, you probably don't want to embed keys from the \index{where + option} family within a \index{for step=\index{tree}}, as this results in two nested loops. It + is more usual to use an \index{conditional>if} family key there. For an example where using + \index{where option} actually does the wrong thing, see question + \href{http://tex.stackexchange.com/questions/167978/smaller-roofs-for-forest}{Smaller roofs for + forest} on \TeX\ Stackexchange. +\end{advise} + +\begin{syntax} \indexitem{propagator>where}|=|\meta{value}\meta{true keylist}\meta{false keylist} \itemnosep \indexitem{word prefix=option>conditional>where=\meta{option}}|=|\meta{value}\meta{true keylist}\meta{false keylist} \itemnosep +\indexitem{word prefix=boolean option>conditional>where=\meta{boolean option}}|=|\meta{true keylist}\meta{false keylist} +\itemnosep \indexitem{word prefix=toks option>conditional>where in=\meta{toks option}}|=|\meta{toks}\meta{true keylist}\meta{false keylist} \itemnosep +\indexitem[set={ + index format={result=where \protect\meta{dimen option}\protect\greaterthan,pgfkey}, + print format={result/.option=argument,+result={where\ },result+={>}, pgfkey}, +}]{conditional>where dimen GT=\protect\meta{dimen option}}|=|\meta{value}\meta{true keylist}\meta{false keylist} +\itemnosep +\indexitem[set={ + index format={result=where \protect\meta{dimen option}<,pgfkey}, + print format={result/.option=argument,+result={where\ },result+={>}, pgfkey}, +}]{conditional>where dimen LT=\protect\meta{dimen option}}|=|\meta{value}\meta{true keylist}\meta{false keylist} +\itemnosep +\indexitem[set={ + index format={result=where \protect\meta{count option}\protect\greaterthan,pgfkey}, + print format={result/.option=argument,+result={where\ },result+={>}, pgfkey}, +}]{conditional>where count GT=\protect\meta{count option}}|=|\meta{value}\meta{true keylist}\meta{false keylist} +\itemnosep +\indexitem[set={ + index format={result=where \protect\meta{count option}<,pgfkey}, + print format={result/.option=argument,+result={where\ },result+={>}, pgfkey}, +}]{conditional>where count LT=\protect\meta{count option}}|=|\meta{value}\meta{true keylist}\meta{false keylist} +\itemnosep \indexitem{step>where nodewalk valid}|=|\meta{toks: nodewalk name}\meta{true keylist}\meta{false keylist} \itemnosep \indexitem{step>where nodewalk empty}|=|\meta{toks: nodewalk name}\meta{true keylist}\meta{false keylist} \itemnosep \indexitem{step>where in saved nodewalk}|=|\meta{nodewalk}\meta{toks: nodewalk name}\meta{true keylist}\meta{false keylist} +\end{syntax} -These keys execute their corresponding |if ...| conditional for every node in the subtree of the current node (including the node itself). In other words: -\begin{center} - |where ...|\meta{arg$_1$}\dots\meta{arg$_1$}|/.style={for tree={if ...=|\meta{arg$_1$}\dots\meta{arg$_1$}|}}| -\end{center} +\subsection{Loops} +\label{ref:loops} + +All loops take a \meta{keylist} argument. The interpretation of the keys in these keylists depends +on the environment the loop appears in. If it is a part of a nodewalk specification, +the keys are taken to be nodewalk keys (\S\ref{ref:nodewalks}), otherwise node keys +(\S\ref{ref:node-keys}). +All loops can be nested safely. + + +\begin{syntax} + \indexitem{loop>repeat}|=|\meta{number}\meta{keylist} The \meta{keylist} is processed \meta{number} times. The \meta{number} expression is evaluated using |pgfmath|. -\indexitem{loop>while}|=|\meta{pgfmath condition}\meta{keylist} +\indexitem{loop>while}|=|\index{forestmath=condition}\meta{keylist} \itemnosep -\indexitem{loop>do while}|=|\meta{pgfmath condition}\meta{keylist} +\indexitem{loop>do while}|=|\index{forestmath=condition}\meta{keylist} \itemnosep -\indexitem{loop>until}|=|\meta{pgfmath condition}\meta{keylist} +\indexitem{loop>until}|=|\index{forestmath=condition}\meta{keylist} \itemnosep -\indexitem{loop>do until}|=|\meta{pgfmath condition}\meta{keylist} +\indexitem{loop>do until}|=|\index{forestmath=condition}\meta{keylist} \keyname{while} loops cycle while the condition is true, \keyname{until} loops terminate when the condition becomes true. @@ -4494,13 +4977,13 @@ These keys execute their corresponding |if ...| conditional for every node in th keylist is executed at least once. The variants without the \keyname{do} prefix check the condition before processing the \meta{keylist}, which might therefore not be processed at all. - When \meta{pgfmath condition} is an empty string, condition \index{valid} is implicitely used, + When \index{forestmath=condition} is an empty string, condition \index{valid} is implicitely used, and \meta{keylist} is implicitely embedded in \index{nodewalk key>on invalid}|=fake|. Thus, the |while| loops will cycle until they ``walk out of the tree'', and |until| loops will cycle until they ``walk into the tree.'' \begin{advise} - \item If a loop ``walks out of the tree'', you can get it back in using \index{last valid} or + \item If a loop ``walks out of the tree'', you can get it back in using \index{step>last valid} or \index{nodewalk key>strip fake steps}. \end{advise} @@ -4535,12 +5018,19 @@ These keys execute their corresponding |if ...| conditional for every node in th \meta{nodewalk} is embedded within \index{nodewalk key>on invalid}|=fake|. -\indexitem(0){loop>break}|=|$n$ Break out of the loop. +\indexitem(0){node key>break}|=|$n$ Break out of the loop. The loop is only exited after all the keys in the current cycle have been processed. The optional argument $n$ ($n\geq0$) specifies which level of embedding to break from; the default is to break out of the innermost loop. + +\indexitem(0){pgfmath>forestloopcount}([$n$]) + + How many times has the loop repeated until now? + + The optional argument $n$ ($n\geq0$) specifies the level of embedding to provide information for; + the default is to count the repetitions of the current, most deeply embedded loop. \end{syntax} @@ -4586,9 +5076,10 @@ A dynamic tree operation is made in two steps: \item Such a two-stage approach is employed because changing the tree structure during the dynamic tree key processing would lead to an unmanageable order of keylist processing. \item A consequence of this approach is that nested dynamic tree keys take several cycles to - complete. Therefore, be careful when using \index{delay} and dynamic tree keys - simultaneously: in such a case, it is often safer to use \index{before typesetting nodes} - instead of \index{delay}, see example (\ref{ex:append}). + complete. Therefore, be careful when using \index{delay} and dynamic tree keys simultaneously: in + such a case, it is often safer to use \index{before typesetting nodes} instead of \index{delay}, + see example (\ref{ex:append}), and it is also possible to define additional stages, see + \S\ref{sec:workflow}. \item Examples: title page (in style |random tree|) and (\ref{ex:niceemptynodes}) (in style |xlist|). \end{advise} @@ -4712,6 +5203,12 @@ real, geometric root of the current node. To access the formal root, use nodewa \subsection{Handlers} \label{ref:handlers} +Handlers are a powerful mechanism of |pgfkeys|, documented in \citep[\S82.3.5]{tikzpgf3.0.0}. +Handlers defined by \foRest; perform a computation and invoke the handled key with its result. The +simple handlers are documented in this section: for \index{handler>process}, see +\S\ref{ref:argument-processor}; for aggregate function handlers, see +\S\ref{ref:aggregate-functions}. + \begin{syntax} \indexitem{handler>option}|=|\meta{option} @@ -4747,88 +5244,518 @@ The result is the (single) expansion of the given Like \index{wrap $n$ pgfmath args} would work for $n=1$. -\indexitem{handler>process args}|=|\meta{argument types}\meta{arg $1$}\dots\meta{arg $n$} - The result is a list of processed arguments. Arguments - are processed individually according to their given type. The types are given sequentially in - \meta{argument types}, one character (no spaces) for each argument. The meanings of the characters are given in the table below. The exception to the one character -- one argument rule are characters - connected by |+|, which apply iteratively (in the given order) to a single argument. If the - argument type list is shorter than the number of argument, the remaining arguments are assumed to - require no processing. +\end{syntax} + +\subsection{Argument processor} +\label{ref:argument-processor} + +For a gentle(r) introduction to the argument processor, see \S\ref{tut:wrapping}. + +The argument processor takes a sequence of instructions and an arbitrary number of arguments and +transforms the given arguments according to the instructions. There are two ways to invoke the +argument processor: + +\begin{syntax} - \begin{tabular}{ll} - |__|&no processing\\ - |o|&expand once\\ - |x|&fully expand\\ - |O|&argument is an option name\\ - |R|&argument is a register name\\ - |P|&argument is a pgfmath expression\\ - |r|&the argument should be a comma-separated list: reverse it\\ - |+|&chain processors)\\ - \end{tabular} +\indexitem{handler>process}|=|\meta{instructions}\meta{arg $1$}\dots\meta{arg $n$} + +The result of the computation is passed on to the handled key as a sequence of arguments. Any +number of arguments can be returned.\footnote{For backward compatibility, \index{handler>process} is also + available as \indexdef{handler>process args}.} + +\item \indexdef{meta>forestmath} = \meta{pgfmath}\OR|>|\meta{instructions}\meta{arg + $1$}\dots\meta{arg $n$} + + In words, a \index{forestmath} expression is either a \meta{pgfmath} expression or an argument + processor expression prefixed by |>|. + + In other words, \FoRest; accepts an argument processor expression anywhere\footnote{The only + exceptions to the above rule are handler \index{pgfmath} and argument processor instruction + \index{processor>P}.} it accepts a \meta{pgfmath} expression. To indicate that we're providing + an argument processor expression, we prefix it with |>|. + + The result of argument processor's computation should be a single item. + +\end{syntax} + + +The syntax of argument processor is a cross between |expl3|'s function argument specification and a +Turing machine, spiced with a bit of reversed Polish notation. ;-) + +Think of \meta{instructions} as a program and \meta{arg $1$}\dots\meta{arg $n$} as the data that +this program operates on. + +If you're familiar with Turing machines: like a Turing machine, the argument processor has a notion +of a head; unlike a Turing machine, the argument processor head is positioned not over some +argument, but between two arguments. If you're not familiar with Turing machines: imagine the +arguments as items on a tape and the argument processor as a head that is always located between +some two items. As the head is between two arguments, we can talk about the arguments on the left +and the arguments on the right. + +In general, an instruction will take some items from the left and some from the right (deleting them +from the tape), perform some computation and insert the result on the tape, some result items to the +left and some to the right. However, most instructions simply take an item from the right, do +something with it, and put the (single-item) result to the left; in effect, the head is moved one +item to the right. At the beggining, all the arguments are always on the right, so the general idea +is that the program will walk through the given arguments, processing them in order. + +Descriptions of individual instructions, given below, contain (at the right edge of the page) the +argument specification, which tells us about the number of input and output items and the movement +of the head. The input and output are separated by an arrow ($\longrightarrow$), and the green eye +(\textcolor{darkgreen}{\eye}) signifies the position of the head with respect to the (input or +output) items. + +For example, instruction \index{processor>O}, which converts an option name into the option value, +exemplifies the most common scenario: it takes one argument from the right and puts the result to +the left (in other words, the head moves one item to the right). Wrapping instrucion +\index{processor>w} is more complicated. Given instruction \index{processor>w}$n$, the argument +processor takes one argument from the right (the wrapping macro body) and $n$ items from the left +(which become the arguments of the wrapping macro), and puts the resulting item to the left. +Comparisons and boolean operations are the instructions resembling the reverse Polish notation: they +take the arguments from the left and put the result to the left, as well. Finally, it is worth +mentioning instructions \index{processor>noop} and \index{processor>+}, which simply move the head +to the right and left, respectively; given that the usual movement of the head is to the right, +\index{processor>+} can be thought of as a process-the-argument-again instruction. + + +Before we finally list the available instructions, some notes: +\begin{itemize} +\item \meta{Instructions} may be given in braces or not. If not, everything until the first opening + brace is considered to be an instruction. +\item An argument item (\meta{arg$_k$}) is a standard \TeX\ macro argument: either a token or a + braced token list. (The obvious exception: \meta{arg$_1$} needs to be braced if it follows + braceless instructions.) +\item Spaces in \meta{instructions} and between arguments are ignored. Format your \index{handler>process} + as you wish! +\item Instructions followed by [$n$] below take an optional numeric modifier. + \begin{itemize} + \item The modifier should be given within the instruction string itself, immediately following the + instruction. In particular, no spaces are allowed there. (Sorry for the little white lie + above.) The number should not be enclosed in braces, even if it is more than one digit long. + \item This modifier is always optional: its default value varies from instruction to instruction. + (Providing $0$ means to use the default.) + \item Unless noted otherwise, the optional numerical argument $n$ instruct the argument processor + to repeat the previous instruction $n$ times (by default, 1). For example, + \index{processor>O}|3| is equivalent to + \index{processor>O}\index{processor>O}\index{processor>O}. + \end{itemize} +\end{itemize} + + +\NewDocumentEnvironment{indexitemprocessinstruction}{ + D(){} % default + O{} % \index [] + m % instruction char + D(){} % instruction modifiers + m % first line + >{\ReverseBoolean} s % typeset processor signature? + >{\SplitArgument {3} {&} } m % processor signature + o % instruction in signature +}{% + \indexitem(#1)[set={#2}]{processor>#3}#4 #5% + \edef\ins{\noexpand\texttt{\IfNoValueTF{#8}{\detokenize{#3}}{#8}}}% + \IfBooleanT{#6}{\hfill\processorsignature#7}% + +}{} + +\newcommand\processorsignature[4]{% + #1 \textcolor{darkgreen}{\eye} #2 + $\longrightarrow$ + #3 \textcolor{darkgreen}{\eye} #4% +} + + +\begin{syntax} + +\begin{indexitemprocessinstruction}[form=\_,index key=_]{noop}([$n$]){no-op} + {&\meta{arg}&\meta{arg}&}[\_] + + The argument is not processed, but simply skipped over. In other words, this instruction only + moves the head one item to the right. (This is like |expl3|'s argument specifier |n|.) + + $n$ means repetition. + + When the end of the instructions is reached, any remaining arguments on the right are processed + using this no-op instruction. + +\end{indexitemprocessinstruction} + +\begin{indexitemprocessinstruction}{o}([$n$]){expand \emph{o}nce} + {&\meta{arg}&\meta{result}&} + + \meta{arg} is expanded once. (This is like |expl3|'s argument specifier |o|). + + The operation is repeated $n$ times (default, one) without moving the head between the + repetition. For example, |o3| expands the argument three times (and then moves the head right). +\end{indexitemprocessinstruction} + +\begin{indexitemprocessinstruction}{x}{fully e\emph{x}pand} + {&\meta{arg}&\meta{result}&} + + \meta{arg} is fully expanded using |\edef|. (This is like |expl3|'s argument specifier |x|.) +\end{indexitemprocessinstruction} + +\begin{indexitemprocessinstruction}{O}([$n$]){\emph{o}ption} + {&\meta{option}&\meta{result}&} + + \meta{option}=\alternative{\meta{option name},\meta{relative node name}\texttt{.}\meta{option name}} + + In the former case, \meta{result} is the value of option at the current node, in the latter, the + value of option at the node referred to by \meta{relative node name}. + + $n$ means repetition. + +\end{indexitemprocessinstruction} + +\begin{indexitemprocessinstruction}{R}([$n$]){\emph{r}egister} + {&\meta{register}&\meta{result}&} + + \meta{result} is the value of register \meta{register}. + + $n$ means repetition. + +\end{indexitemprocessinstruction} + +\begin{indexitemprocessinstruction}{P}([$n$]){\emph{p}gfmath} + {&\meta{pgfmath expr}&\meta{result}&} - Example: \index{split option} is defined by preprocessing the first argument of \index{split} - as an option. -\lstinputregion{forest.dtx}{split_option} + \meta{result} is the result of evaluating \meta{pgfmath expr} using |\pgfmathparse|. -\begin{forestexample}[index={delay,append,strequal,split,process args}] + $n$ means repetition. + + Combining \index{processor>P} and \index{processor>w}, \index{handler>process} is capable of anything + \index{wrap $n$ pgfmath args} can do. Even better, as we can combine pgfmath and non-pgfmath + methods, computations that use \index{handler>process} can be (much!) faster. Study the following + examples to see how less and less pgfmath is used to achieve the same result --- but note that + such extreme antipgfmathism probably only makes sense for style/package developers in computations + that get performed many times. + +\begin{forestexample}[index={handler>process,processor>w,processor>O,processor>W,processor>P,processor>+}] + \begin{forest} + [,grow'=east, where level=1{}{phantom,ignore,ignore edge} + [(a),delay={content/.wrap 4 pgfmath args={#1 $#2*#3=#4$} + {content}{content("!1")}{content("!2")}{int(content("!1")*content("!2"))}} + [6][7]] + [(b),delay={content/.process={O OO~P~ w4} + {content} + {!1.content}{!2.content}{int(content("!1")*content("!2"))} + {#1 $#2*#3=#4$}} + [6][7]] + [(c),delay={content/.process={O OO ~W2+P~ w4} + {content} + {!1.content}{!2.content}{int(#1*#2)} + {#1 $#2*#3=#4$}} + [6][7]] + [(d),delay={content/.process={O OO ~W2+n~ w4} + {content} + {!1.content}{!2.content}{#1*#2} + {#1 $#2*#3=#4$}} + [6][7]] + ] + \end{forest} +\end{forestexample} + + +\end{indexitemprocessinstruction} + +\begin{indexitemprocessinstruction}{n}([$n$]){\emph{n}umexpr} + {&\meta{numexpr}&\meta{result}&} + + \meta{result} is the result of evaluating \meta{dimexpr} using e\TeX's |\number\numexpr|. + + $n$ means repetition. + +\end{indexitemprocessinstruction} + +\begin{indexitemprocessinstruction}{d}([$n$]){\emph{d}imexpr} + {&\meta{dimexpr}&\meta{result}&} + + \meta{result} is the result of evaluating \meta{dimexpr} using e\TeX's |\the\dimexpr|. + + $n$ means repetition. + +\end{indexitemprocessinstruction} + +\begin{indexitemprocessinstruction}{+}([$n$]){chain instructions} + {\meta{arg}&&&\meta{arg}} + + This action allows one to ``process the same argument more than once''. It does not process the + current argument (in fact, there need not be any current argument), but rather moves the last + result back in the argument queue. In other words, our machine's head moves one step left. You + can also imagine it as an inverse of \index{processor>noop}. + + $n$ means repetition. + +\end{indexitemprocessinstruction} + +\begin{forestexample}[index={handler>process,processor>O,processor>noop}] \begin{forest} - [ - {1,2,3,4,5}, - delay={ - my append/.style={if={strequal("#1","")}{}{append={[#1]}}}, - split/.~process args~={O+r}{content}{,}{my append}, - } - ] + test/.style n args={3}{align=center, + content={The value of my option \texttt{#1} is \texttt{#2}.\\#3}} + [~fit~,delay={test/.process={O ~O+O~}{content}~{content}~{Yes it is!}}] \end{forest} \end{forestexample} + +\begin{indexitemprocessinstruction}{w}([$n$]){(consuming) \emph{w}rap} + {\meta{arg$_{1}$}\dots\meta{arg$_{n}$}&\meta{macro body}&\meta{result}&} +\end{indexitemprocessinstruction} +\itemnosep[2pt] +\begin{indexitemprocessinstruction}{W}([$n$]){(non-consuming) \emph{w}rap} + {\meta{arg$_{1}$}\dots\meta{arg$_{n}$}&\meta{macro body}& + \meta{arg$_{1}$}\dots\meta{arg$_{n}$}\meta{result}&} + + Defines a temporary macro with $n$ undelimited arguments using the \meta{macro body} given on the + right and expands it (once). The arguments given to the temporary macro are taken from the left: + \meta{arg$_{1}$}\dots\meta{arg$_{n}$}. The result of the expansion is stored as \meta{result} to + the right. + + With |w|, \meta{arg$_{1}$}\dots\meta{arg$_{n}$} are ``consumed'', i.e.\ they are removed from the + result list on the left. |W| keeps \meta{arg$_{1}$}\dots\meta{arg$_{n}$} in the result list. + + Default $n$ is 1. (Specifying $n>9$ raises an error.) +\end{indexitemprocessinstruction} + +\begin{indexitemprocessinstruction}[form={\&},index key=\&]{and}([$n$]){boolean ``and''}*{} +\end{indexitemprocessinstruction} +\itemnosep[2pt] +\begin{indexitemprocessinstruction}[form={\protect\indexpipe},index key=\&or]{or}([$n$]){boolean ``or''} + {\meta{arg$_{1}$}\meta{arg$_{2}$}&&\meta{result}&} + + \meta{result} is a boolean conjunction/disjunction of $n$ arguments. The arguments are taken from + the left. They should be numbers (positive integers): |0| means false, any other number means + true. The \meta{result} is always |0| or |1|. + + Default $n$ is 2. +\end{indexitemprocessinstruction} + +\begin{indexitemprocessinstruction}[form={!},index key=!]{not}{boolean ``not''} + {\meta{arg}&&\meta{result}&} + + \meta{result} is a boolean negation of the argument. The argument is taken from the left. It + should be a number (positive integer): |0| means false, any other number means true. The + \meta{result} is always |0| or |1|. +\end{indexitemprocessinstruction} + +\begin{indexitemprocessinstruction}{?}{conditional (if \dots\ then\dots\ else)} + {\meta{condition}&\meta{true arg}\meta{false arg}&&\meta{result}} + + \meta{result} is \meta{true arg} is \meta{condition} is true (non-zero), otherwise \meta{false + arg}. + + The condition is taken from the left. The true and false arguments are expected on the right, + where the winner is left as well. +\end{indexitemprocessinstruction} + +\begin{indexitemprocessinstruction}[form={=},index key={=}]{equal}{comparison: $\meta{arg$_{1}$}=\meta{arg$_{2}$}$?}*{} +\end{indexitemprocessinstruction} +\itemnosep[1pt] +\begin{indexitemprocessinstruction}[form={<},index key={<}]{lt}{comparison: $\meta{arg$_{1}$}<\meta{arg$_{2}$}$?}*{} +\end{indexitemprocessinstruction} +\itemnosep[1pt] +\begin{indexitemprocessinstruction}[form={\protect\greaterthan},index key={<<}]{gt}{comparison: $\meta{arg$_{1}$}>\meta{arg$_{2}$}$?} + {\meta{arg$_{1}$}\meta{arg$_{2}$}&&\meta{result}&} + + Compare \meta{arg$_{1}$} and \meta{arg$_{2}$}, returning |1| (true) if \meta{arg$_{1}$} is equal + to / less than / greater than \meta{arg$_{2}$}, |0| (false) otherwise. + + The arguments are taken from the left. They can be either numbers, dimensions, text or token + lists. Both arguments are expected to be of the same type. The type of comparison is determined + by the type of the result returned by the last instruction. + \index{processor>O}/\index{processor>R} look up the type of option/register to determine the type + (booleans are numbers and keylists are toks). Text type must be marked explicitely using + \index{processor>t}. + + Comparison is carried out using |\ifnum| for numbers, |\ifdim| for dimensions (this includes + unitless decimals returned by pgfmath) and |\pdfstrcmp|\footnote{\texttt{\string\pdfstrcmp} + expands its arguments.} for text --- for these three types, all three comparison operators are + supported. For generic token lists, only |=| makes sense and is carried out using |\ifx|. + + In the following example, (a) performs lexicographical comparison because we have marked |21| as + text; (b) and (c) perform numeric comparison: in (b), the type is automatically determined from + the type of register \indexex{tempcounta}, in (c) |21| is marked manually using \index{processor>n}. + +\begin{forestexample}[index={if,processor>gt,processor>lt}] + \forestset{ + tempcounta=100, + TeX/.process={Rw1}{tempcounta}{$#1>21$?\ }, + TeX={(a)\ }, if={>{Rt>}{tempcounta}{21}}{TeX=yes}{TeX=no},TeX={,\ }, + TeX={(b)\ }, if={>{_R<}{21}{tempcounta}}{TeX=yes}{TeX=no},TeX={,\ }, + TeX={(c)\ }, if={>{Rn>}{tempcounta}{21}}{TeX=yes}{TeX=no}, + } +\end{forestexample} + +\end{indexitemprocessinstruction} + +\begin{indexitemprocessinstruction}{t}{mark as \emph{t}ext} + {&\meta{arg}&\meta{arg}&} + + The result is not changed, only its type is changed to text. This is relevant only for + comparisons --- both argument processor's comparisons \index{processor>equal}, \index{processor>gt} + and \index{processor>lt} and sort keys (see \index{sort by}). +\end{indexitemprocessinstruction} + +\begin{indexitemprocessinstruction}{c}{to lowercase} + {&\meta{arg}&\meta{result}&} +\end{indexitemprocessinstruction} + +\begin{indexitemprocessinstruction}{C}{to uppercase} + {&\meta{arg}&\meta{result}&} +\end{indexitemprocessinstruction} + +\begin{indexitemprocessinstruction}{-}{toggle ascending/descending order (negate)} + {\meta{arg}&&\meta{result}&} + + If the argument is of the text type, its sorting order is changed from ascending to descending or + vice versa. + + For any numerical argument type (number, dimension, unitless dimension), the argument is actually + negated, which obviously has the same effect on sorting. + + For generic type arguments, this operation is a no-op. +\end{indexitemprocessinstruction} + +\begin{indexitemprocessinstruction}{u}{\emph{u}ngroup} + {&\meta{arg}&&\meta{item$_1$}\dots\meta{item$_n$}} + + As every \TeX\ undelimited macro argument, \meta{arg} is a list of tokens or braced token lists. + This instruction puts those items back to the right as ``separate arguments''. +\end{indexitemprocessinstruction} + +\begin{indexitemprocessinstruction}{s}([$n$]){(consuming) \emph{s}ave} + {\meta{arg$_{1}$}\dots\meta{arg$_{n}$}&&&} +\end{indexitemprocessinstruction} +\itemnosep[2pt] +\begin{indexitemprocessinstruction}{S}([$n$]){(non-consuming) \emph{s}ave} + {\meta{arg$_{1}$}\dots\meta{arg$_{n}$}&&\meta{arg$_{1}$}\dots\meta{arg$_{n}$}&} + + Saves the last $n$ arguments from the left into a ``special place''. + + With |s|, \meta{arg$_{1}$}\dots\meta{arg$_{n}$} are ``consumed'', i.e.\ they are removed from the + result list on the left. |S| keeps \meta{arg$_{1}$}\dots\meta{arg$_{n}$} in the result list. + + Default $n$ is 1. +\end{indexitemprocessinstruction} + +\begin{indexitemprocessinstruction}{l}([$n$]){(consuming) \emph{l}oad} + {&&\meta{arg$_{1}$}\dots\meta{arg$_{n}$}&} +\end{indexitemprocessinstruction} +\itemnosep[2pt] +\begin{indexitemprocessinstruction}{L}([$n$]){(non-consuming) \emph{l}oad} + {&&\meta{arg$_{1}$}\dots\meta{arg$_{n}$}&} + + Loads $n$ arguments from the ``special place'' to the left. + + With |l|, \meta{arg$_{1}$}\dots\meta{arg$_{n}$} are ``consumed'', i.e.\ they are removed from the + special place. |S| keeps \meta{arg$_{1}$}\dots\meta{arg$_{n}$} in the special place. + + The default $n$ is 0 and indicates that the entire special place should be loaded. +\end{indexitemprocessinstruction} + +\begin{indexitemprocessinstruction}{r}{\emph{r}everse (key)list} + {&\meta{list}&\meta{result}&} + + \meta{list} should be a comma-separated list (\emph{not} a name of a keylist option or register). + \meta{result} contains the same elements in the reverse order. +\end{indexitemprocessinstruction} + \end{syntax} -\subsubsection{Aggregate functions} + + + + +\subsection{Aggregate functions} \label{ref:aggregate-functions} -Aggregate functions are defined as handlers over options. They walk a nodewalk, use the values of visited options to calculate something, and store the result in the handled option. +Aggregate functions walk a nodewalk and use the information found in the visited nodes to calculate +something. + +All aggregate functions are available both as key handlers and |pgfmath| functions. + -Aggregate functions cannot be nested. \begin{syntax} - \indexitem{aggregate>count}|=|\meta{nodewalk} + \indexitem{aggregate>count}|=|\meta{nodewalk}, + \indexdef[form={aggregate_count}]{pgfmath>aggregate count}|("|\meta{nodewalk}|")| Store the number of nodes visited in the nodewalk into the handled option. -\indexitem{aggregate>sum}|=|\meta{pgfmath}\meta{nodewalk}\itemnosep -\indexitem{aggregate>average}|=|\meta{pgfmath}\meta{nodewalk}\itemnosep -\indexitem{aggregate>product}|=|\meta{pgfmath}\meta{nodewalk}\itemnosep -\indexitem{aggregate>min}|=|\meta{pgfmath}\meta{nodewalk}\itemnosep -\indexitem{aggregate>max}|=|\meta{pgfmath}\meta{nodewalk} - - Calculate the value of \meta{pgfmath} expression at each visited node. Store the sum / average / product / minimum / maximum of these values into the handled option. - -\indexitem{aggregate>aggregate}|=|\meta{pgfmath: start value}\meta{pgfmath: every step}\meta{pgfmath: after walk}\meta{nodewalk} - - The generic aggregate function. First, the result is set to \meta{pgfmath: start value}. Then, - the given nodewalk is walked. After each step of the \meta{nodewalk}, \meta{pgfmath: every step} expression is evaluated in the context of the new current node and stored as the result. After the walk, the current node is reset to the origin. \meta{pgfmath: after walk} expression is then evaluated in its context and stored as the result. - - Use (appropriately escaped) |#1| to refer to the current value of the result in \meta{pgfmath: - every step} and \meta{pgfmath: after walk}. Use count register \index{aggregate n} to refer - to the current step number (in \meta{pgfmath: every step}) or the total number of steps (in \meta{pgfmath: after walk}) - - Example 1: see \index{option>s}. - - Example 2: the definition of \index{aggregate>average} below. Note that as we are using - |.aggregate| inside a style definition, |##1| must be used to refer to the current value of the - result. -\begin{lstlisting}[] - /handlers/~.average~/.style 2 args={ - /handlers/~.aggregate~= - {0} - {(##1)+(#1)} - {##1/\forestregister{aggregate n}} - {#2} - } -\end{lstlisting} - Example 3: randomly generate the content of leaves; the content of a parent is the sum of it's children's content. +\indexitem{aggregate>sum}|=|\index{forestmath}\meta{nodewalk}, +\indexdef[form={aggregate_sum}]{pgfmath>aggregate sum}|("|\index{forestmath}|","|\meta{nodewalk}|")| +\itemnosep + +\indexitem{aggregate>average}|=|\index{forestmath}\meta{nodewalk}, +\indexdef[form={aggregate_average}]{pgfmath>aggregate average}|("|\index{forestmath}|","|\meta{nodewalk}|")| +\itemnosep + +\indexitem{aggregate>product}|=|\index{forestmath}\meta{nodewalk}, +\indexdef[form={aggregate_product}]{pgfmath>aggregate product}|("|\index{forestmath}|","|\meta{nodewalk}|")| +\itemnosep + +\indexitem{aggregate>min}|=|\index{forestmath}\meta{nodewalk}, +\indexdef[form={aggregate_min}]{pgfmath>aggregate min}|("|\index{forestmath}|","|\meta{nodewalk}|")| +\itemnosep + +\indexitem{aggregate>max}|=|\index{forestmath}\meta{nodewalk}, +\indexdef[form={aggregate_max}]{pgfmath>aggregate max}|("|\index{forestmath}|","|\meta{nodewalk}|")| + +Calculate the value of the given \index{forestmath} expression at each visited node. Store the sum / +average / product / minimum / maximum of these values into the handled option (handlers) or return +it (pgfmath functions). + +\indexitem{aggregate>aggregate}|=|\index{forestmath=start value}\index{forestmath=every + step}\index{forestmath=after walk}\meta{nodewalk} +\itemnosep +\indexitem{pgfmath>aggregate}|("|\index{forestmath=start value}|","|\index{forestmath=every step}|","|\index{forestmath=after walk}|","|\meta{nodewalk}|")| + +The generic aggregate function. First, register \index{aggregate result} is set to +\index{forestmath=start value}. Then, the given nodewalk is walked. After each step of the +\meta{nodewalk}, \index{forestmath=every step} expression is evaluated in the context of the new +current node and stored into \index{aggregate result}. After the walk, the current node is reset to +the origin. \index{forestmath=after walk} expression is then evaluated in its context and stored +into \index{aggregate result} as the final result. + +Use \index{aggregate result} and \index{aggregate n} in the \index{forestmath} expressions to refer to +the current result value and step number. + +\indexitem{register>aggregate n}|=|\meta{count} the current step number + +In the every-step expression of an aggregate function, refers to the (real) step number in the +aggregate's \meta{nodewalk}. In the after-walk expression, refers to the total number of (real) +steps made. + +\indexitem{register>aggregate result}|=|\meta{toks} the current value of the result + + This register is where the intermediate results are stored. + +\indexitem{register>aggregate value}|=|\meta{toks} the value of the expression at the current node + +This only applies to special aggregates like \index{aggregate>sum}, not to the generic +\index{aggregate>aggregate}. + +\indexitem{node key>aggregate postparse}|=|\alternative{none,int,print,macro} + +Roughly speaking, how should the result be formatted? For details, see \citep[\S89]{tikzpgf3.0.0}. +Applies only to |pgfmath| versions of aggregate functions, i.e.\ not to the |'| variants. + + \begin{syntax} + \item\indexdef{value of=aggregate postparse>none} + No formatting. + \item\indexdef{value of=aggregate postparse>int} + The result is an integer. + \item\indexdef{value of=aggregate postparse>print} + Use |pgf|'s number printing extension, see \citep[\S93]{tikzpgf3.0.0}. + \item\indexdef{value of=aggregate postparse>macro} + Use a custom macro. Specify the macro using \indexdef{node key>aggregate postparse macro}|=|\meta{cs}. + \end{syntax} + +\end{syntax} + +Example 1. Randomly generate the content of leaves. The content of a parent is the sum of its +children's content. Note how we use \indexex{tree children-first} to proceed in a bottom-up +fashion. \begin{forestexample}[index={delay,aggregate postparse,for step,tree children-first,if option,n children,content,pgfmath,sum,step>children}] \begin{forest} @@ -4843,27 +5770,35 @@ Aggregate functions cannot be nested. [[[[][]][]][[][][[][][]]][[][[][]]]] \end{forest} \end{forestexample} - -\indexitem{register>aggregate n}|=|\meta{count} - In the every-step expression of an aggregate function, refers to the (real) step number in the aggregate's \meta{nodewalk}. In the after-walk expression, refers to the total number of (real) steps made. -\indexitem{node key>aggregate postparse}|=|\alternative{none,int,print,macro} + Example 2: nested aggregate functions. We are given the black numbers. The inner aggregate, the + sum of children, is applied at every blue node. (See how we actually display the blue numbers by + storing \index{aggregate value} to \index{content}.) The outer aggregate stores the maximum blue + number into the red root. - Roughly speaking, how should the result be formatted? For details, see \citep[\S89]{tikzpgf3.0.0}. +\begin{forestexample} + \begin{forest} + delay={ + aggregate postparse=int, + content/~.max~=% + {~aggregate_sum~("content","children")}% + {every step={content/.register=~aggregate value~},children}% + } [ [[1][2][3]] [[3][4][5]] [[2][3][4]] ] + \end{forest} +\end{forestexample} - \begin{syntax} - \item\indexdef{value=aggregate postparse>none} - No formatting. - \item\indexdef{value=aggregate postparse>int} - The result is an integer. - \item\indexdef{value=aggregate postparse>print} - Use |pgf|'s number printing extension, see \citep[\S93]{tikzpgf3.0.0}. - \item\indexdef{value=aggregate postparse>macro} - Use a custom macro. Specify the macro using \indexdef{node key>aggregate postparse macro}|=|\meta{cs}. - \end{syntax} - -\end{syntax} +Example 3: calculate root mean square of children using the generic \index{aggregate>aggregate} handler. +\begin{forestexample} + \begin{forest} + delay={ + content/~.aggregate~= + {0}{~aggregate_result~()+content()^2}{sqrt(~aggregate_result~/~aggregate_n~)} + {children} + } + [[0][1][2][3][4]] + \end{forest} +\end{forestexample} \subsection{Relative node names} \label{ref:relative-node-names} @@ -4902,9 +5837,9 @@ The explicit \texttt{forest} coordinate system is called simply |forest| and use is a keylist; the following keys are accepted. \begin{syntax} -\indexitem{forest cs>name}|=|\meta{node name} The node with the given name becomed the current node. The +\indexitem{forest cs>name}|=|\meta{node name} The node with the given name becomes the current node. The resulting point is its (node) anchor. -\indexitem{forest cs>id}|=|\meta{node id} The node with the given name becomed the current node. The +\indexitem{forest cs>id}|=|\meta{node id} The node with the given name becomes the current node. The resulting point is its (node) anchor. \indexitem{forest cs>go}|=|\meta{nodewalk} Walk the given nodewalk, starting at the current node. The node at the end of the walk becomes the current node. The resulting point is its (node) anchor. @@ -4930,6 +5865,7 @@ The resulting point is computed only after both \index{option>l} and \index{opti \FoRest; defines several anchors which can be used with any \TikZ; node belonging to a \FoRest; tree (manually added \TikZ; nodes are thus excluded). +\newcommand\indexdefneganchor[1]{\indexdef[index key=#1]{anchor>-#1}} \begin{syntax} \indexitem{anchor>parent anchor}\itemnosep \indexitem{anchor>child anchor}\itemnosep @@ -4938,39 +5874,83 @@ tree (manually added \TikZ; nodes are thus excluded). These anchors point to coordinates determined by node options \index{option>parent anchor}, \index{option>child anchor} and \index{option>anchor}. -\indexitem{anchor>parent}, \indexdef{anchor>parent'}\itemnosep -\indexitem{anchor>parent first}, \indexdef{anchor>parent first'}\itemnosep +\indexitem{anchor>parent}, \indexdef{anchor>parent'}, \indexdefneganchor{parent}, \indexdefneganchor{parent'}\itemnosep +\indexitem{anchor>parent first}, \indexdef{anchor>parent first'}, \indexdefneganchor{parent first}, \indexdefneganchor{parent first'}\itemnosep \indexitem{anchor>first}, \indexdef{anchor>first'}\itemnosep -\indexitem{anchor>children first}, \indexdef{anchor>children first'}\itemnosep -\indexitem{anchor>children}, \indexdef{anchor>children}\itemnosep -\indexitem{anchor>children last}, \indexdef{anchor>children last}\itemnosep -\indexitem{anchor>last}, \indexdef{anchor>last}\itemnosep -\indexitem{anchor>parent last}, \indexdef{anchor>parent last} +\indexitem{anchor>children first}, \indexdef{anchor>children first'}, \indexdefneganchor{children first}, \indexdefneganchor{children first'}\itemnosep +\indexitem{anchor>children}, \indexdef{anchor>children'}, \indexdefneganchor{children}, \indexdefneganchor{children'}\itemnosep +\indexitem{anchor>children last}, \indexdef{anchor>children last'}, \indexdefneganchor{children last}, \indexdefneganchor{children last'}\itemnosep +\indexitem{anchor>last}, \indexdef{anchor>last'}\itemnosep +\indexitem{anchor>parent last}, \indexdef{anchor>parent}, \indexdefneganchor{parent last},\indexdefneganchor{parent last'} + Growth direction based anchors. \TikZ;'s ``compass anchors'' |east|, |north| etc.\ resolve to coordinates on the border of the node facing east, north etc.\ (for the shapes that define these anchors). The above \FoRest;'s anchors are similar in that they also resolve to coordinates on the border of the node. However, - the ``cardinal directions'' are determined by the \index{grow}th direction of the tree in the node, so - that + the ``cardinal directions'' are determined by the \index{grow}th direction of the tree in the node + and its parent: + \begin{itemize} \item anchor |parent| faces the parent node (or, in case of the root, where the parent would be); \item anchor |children| faces the children (or, in case of a node without children, where the children would be); \item anchor |first| faces the first child (or \dots\ you get it, right?); \item anchor |last| faces the last child (or \dots\ you know!). \end{itemize} - Combinations like |parent_children| work like combinations of compass directions, e.g.\ - |north_west|. These anchors work as expected even if the node is \index{rotate}d, or if the - children are \index{reversed}. + Combinations like |children_first| work like combinations of compass directions, e.g.\ + |north_west|, but note that + \begin{itemize} + \item when |first| and |last| are combined with |parent| into |parent_first| and |parent_last|, + they refer to the first and last child of the parent node, i.e.\ siblings of the current node. + \end{itemize} + + While |first| and |last| always point in opposite directions, |parent| and |children| do not do so + if the \index{grow}th direction of the tree changes in the node, i.e.\ if the node's \index{grow} + differs from it's parent's \index{grow}. Thus in general, it is useful to have anchors |-parent| + and |-children|, which point in the opposite directions as |parent| and |children|, respectively, + and their combinations with |first| and |last|. The |'| variants refer precisely to the point where the cardinal growth direction intersects the border. Variants without |'| snap to the closest compass anchor of the node. - + + These anchors work as expected even if the node is \index{rotate}d, or if the + children are \index{reversed}. + For simple examples, see definitions of \index{sn edges} and \index{roof}; for more involved examples, see the \reflibrary{edges} library. \end{syntax} +\begin{forestexample}[layout=tree on top] + \def\redorblue#1{\expandafter\redorbluei#1\END}% + \def\redorbluei#1#2\END{\expandafter\ifx#1-red\else blue\fi}% + \forestset{ + draw anchors/.style n args=3{% #1=above, #2=below, #3='-variant of anchor? + tikz={ + \foreach \a in {first,last,parent first,parent last,children,children last,#1} + {\fill[](.\a#3)circle[radius=1pt] node[above,font=\tiny,color=\redorblue\a]{\a#3};} + \foreach \a in {-parent first,-parent,-parent last,-children,-children first,#2} + {\fill[](.\a#3)circle[radius=1pt] node[below,font=\tiny,color=\redorblue\a]{\a#3};} + } + }, + draw anchors/.default={parent,children first}{-children last}{}, + } + \begin{forest} + for tree={ + minimum width=10em, minimum height=13ex, s sep+=5em, + draw, draw anchors, + font=\tt, delay={content/.process=OOw2{grow}{reversed}{grow\ifnum#2=1'\fi=#1}} + } + [ + [,rotate=20,draw anchors={parent,children first}{-children last}{'}] + [,for tree={grow'=0}, l sep+=5em, draw anchors={-children last}{parent,children first}{} + [,rotate=-60] + [] + ] + ] + \end{forest} +\end{forestexample} + \subsection{Additional \texttt{pgfmath} functions} \label{ref:pgfmath} @@ -5016,10 +5996,10 @@ there is one), so strange but useful constructions like the following are possib Boolean function \indexdef{pgfmath>valid} returns true if the node's \index{readonly option>id}$\neq0$, i.e.\ if the node is a real, valid node; see \S\ref{ref:spatial-propagators} and \S\ref{ref:nodewalks}. Boolean function \indexdef{pgfmath>invalid} is a negation of |valid|. \begin{syntax} -\indexitem[set={+format={detokenize}}]{pgfmath>min_l}|=(|\meta{nodewalk: node}|,|\meta{nodewalk: context node}|)| \itemnosep -\indexitem[set={+format={detokenize}}]{pgfmath>min_s}|=(|\meta{nodewalk: node}|,|\meta{nodewalk: context node}|)| \itemnosep -\indexitem[set={+format={detokenize}}]{pgfmath>max_l}|=(|\meta{nodewalk: node}|,|\meta{nodewalk: context node}|)| \itemnosep -\indexitem[set={+format={detokenize}}]{pgfmath>max_s}|=(|\meta{nodewalk: node}|,|\meta{nodewalk: context node}|)| +\indexitem{pgfmath>min_l}|=(|\meta{nodewalk: node}|,|\meta{nodewalk: context node}|)| \itemnosep +\indexitem{pgfmath>min_s}|=(|\meta{nodewalk: node}|,|\meta{nodewalk: context node}|)| \itemnosep +\indexitem{pgfmath>max_l}|=(|\meta{nodewalk: node}|,|\meta{nodewalk: context node}|)| \itemnosep +\indexitem{pgfmath>max_s}|=(|\meta{nodewalk: node}|,|\meta{nodewalk: context node}|)| These functions return the minimum/maximum value of \index{option>l}/\index{option>s} of node at the end of \meta{nodewalk: node} in the context (i.e.\ growth direction) of node at the end of \meta{nodewalk: context @@ -5070,18 +6050,18 @@ anchor,option>anchor,fit,tier,readonly option>level,delay,before typesetting nod \end{forest} \end{forestexample} +{\def\useforestlibrary#1{}% \begin{forestexample}[point=instr,index={where option,n children,tier,content,no edge,tikz},index>={!}] % roof terminal phrases + \useforestlibrary{linguistics} + % ... \begin{forest} - where n children=0{tier=word, - if={~instr~("P",~content~("!u"))}{no edge, - tikz={\draw (!.north west)-- - (!.north east)--(!u.south)--cycle; - }}{} - }{}, + delay={where n children=0{tier=word, + if={~instr~("P",~content~("!u"))}{roof}{} + }{}}, [VP[DP[Mary]][V'[V[loves]][DP[her cat]]]] \end{forest} -\end{forestexample} +\end{forestexample}} \subsection{Standard node} @@ -5262,13 +6242,89 @@ anchor,option>anchor,anchor>anchor,calign,for step,tree,s sep,option>l,n childre \subsection{Changelog} \label{sec:changelog} -First of all, the list of all \index{compat} keys for backward compatibility, and their groupings. +First of all, the list of all \index{compat} key values for backward compatibility, and their +groupings. Remember, compat values that reside in styles with suffix |-most| are harmless: they will +not disrupt the new functionality of the package. But take care when using stuff which only resides +in |-all| styles. \lstinputregion{forest-compat.sty}{compat_keys} +\newcommand\compatitem[2]{\item[,,in \texttt{-#1}]\texttt{compat=}\indexdef{value of=compat>#2}} + +\subsubsection{v2.1} + +\begin{description} +\item[v2.1 (2016/12/05)] \mbox{} + + Backward incompatible changes (with a \index{compat} key): + \begin{syntax} + \compatitem{all}{2.0-edges} + This compat key groups the three changes listed below: the final two depend on the first, so you + will probably want to revert them all or none. + \begin{syntax} + \compatitem{all}{2.0-anchors} + This is really a bugfix. Growth direction based anchors \index{anchor>parent}, + \index{anchor>parent first} and \index{anchor>parent last} were not facing to the direction of the + parent if the growth direction of the tree changed at the node. + \compatitem{all}{2.0-forkededge} + \compatitem{all}{2.0-folder} + Update the code of keys \index{forked edge} (and friends) and \index{folder} from the + \reflibrary{edges} library to reflect the above bugfix. + \end{syntax} + \compatitem{all}{2.0-delayn} Fixing yet another bug in \index{delay n}! The number of cycles was + reevaluated at each cycle. Now it is computed immediately, and fixed. Use this key to revert to + the old behaviour. + \end{syntax} + + Performance: + \begin{itemize} + \item Substantially enhance the argument processor (\S\ref{ref:argument-processor}), including the + ability to use it as a drop-in replacement for |pgfmath|. + \item Internally, avoid using |\pgfmathparse| and friends whereever possible. + \item Implement a fast set of macros to determine if a |pgfmath| expression is just a \meta{count} + or \meta{dimen} expression. + \item Optimize \index{split option} and \index{split register}. + \end{itemize} + Minor improvements: + \begin{itemize} + \item Allow \index{relative node name}s in \index{handler>option}. + \item Make aggregate functions (\S\ref{ref:aggregate-functions}) nestable and implement their + |pgfmath| versions. + \item Implement + \index{if dimen GT=\meta{dimen option}}, \index{if dimen LT=\meta{dimen option}}, + \index{if count GT=\meta{count option}}, \index{if count LT=\meta{count option}}, + \index{where dimen GT=\meta{dimen option}}, \index{where dimen LT=\meta{dimen option}}, + \index{where count GT=\meta{count option}} and \index{where count LT=\meta{count option}}, + \item Implement \index{if current nodewalk empty}. + \item Implement nodewalk steps \index{leaves}, \index{-level} and \index{-level'}. + \item Implement nodewalk operation \index{unique}. + \item Implement \index{nodewalk key>on invalid} values \index{value of=on invalid>error if real} and \index{value of=on invalid>last valid}, remove value |step| (no \index{compat} key, as it was broken and useless). + \item Implement `-` anchors (\index{anchor>-parent} etc.). + \item Implement \index{save and restore register}. + \item Implement \index{handler>nodewalk style}. + \item Implement \index{forestloopcount}. + \item Allow multiple occurrences of package option \index{compat}. + %\item Implement \index{foresttypeouttrees}. + %\item Implement \index{show register}. + \end{itemize} + + Bugfixes: + \begin{itemize} + \item Fix a bug in externalization (|\forest@file@copy| set |\endlinechar| to |-1|, which caused + problems for several packages, e.g. |biblatex|). + \item Fix a bug in \index{delay n}: the number of cycles was reevaluated at each cycle. + \item Fix a bug in \index{fixed edge angles}. + \item Fix \index{compat} key values \index{value of=compat>silent}, \index{value of=compat>1.0-forstep} and \index{value of=compat>1.0-stages}. + \item Fix invocations of spatial propagators \index{for step=\index{step>nodewalk}} and \index{for step=\index{step>Nodewalk}} and \index{node key>Nodewalk}. + \item Fix invocations of \index{for step=group}, \index{for step=next on tier} and \index{for step=previous on tier}. + \item Fix behaviour of \index{for step=next on tier}, \index{for step=previous on tier} and \index{for step=to tier} on arrival to the invalid node. + \item Fix problems with interaction between \index{folder} and \index{forked edges}. + \end{itemize} + +\end{description} + \subsubsection{v2.0} -\newcommand\compatitem[2]{\item[,,in \texttt{-#1}]\texttt{compat=}\indexdef{option of=compat>#2}} \begin{description} \item[v2.0.3 (2016/04/03)] \mbox{} @@ -5276,7 +6332,6 @@ First of all, the list of all \index{compat} keys for backward compatibility, an Backward incompatible changes (with a \index{compat} key): \begin{syntax} \compatitem{all}{2.0.2-delayn} - \itemnosep \compatitem{all}{2.0.2-wrapnpgfmathargs} This is really a bugfix: keys \index{delay n} and \index{wrap $n$ pgfmath args} (for $n\geq 2$) @@ -5411,15 +6466,15 @@ First of all, the list of all \index{compat} keys for backward compatibility, an \begin{tabularx}{\linewidth}{lll} old&new&\index{compat} key {\small (all but the last are in \texttt{-most})}\\\hline - \keyname{node walk}&\index{for step=nodewalk}\footnote{Nodewalks are much improved in v2.0, so some syntax and keys are different than in v1.0!}&\indexdef{option of=compat>1.0-nodewalk}\\ - \keyname{for}&\index{for step=\index{group}}&\indexdef{option of=compat>1.0-for}\\ - \keyname{for all next}&\index{for step=\index{following siblings}}&\indexdef{option of=compat>1.0-forall}\\ - \keyname{for all previous}&\index{for step=\index{preceding siblings}}&\indexdef{option of=compat>1.0-forall}\\ - \keyname{for ancestors'}&\index{for step=\index{current and ancestors}}&\indexdef{option of=compat>1.0-ancestors}\\ - (\keyname{for}) \keyname{linear next}&(\index{for step}) \index{next node}&\indexdef{option of=compat>1.0-linear}\\ - (\keyname{for}) \keyname{linear previous}&(\index{for step}) \index{previous node}&\indexdef{option of=compat>1.0-linear}\\ - \keyname{triangle}&\index{roof} (library \reflibrary{linguistics})&\indexdef{option of=compat>1.0-triangle}\\ - \keyname{/tikz/fit to tree}&\index{fit to}\keyname{=}\index{tree}\footnote{The v1.0 key \keyname{/tikz/fit to tree} also set \keyname{inner sep=0}; the v2.0 key \index{fit to} does not do that.}&\indexdef{option of=compat>1.0-fittotree}\\ + \keyname{node walk}&\index{for step=nodewalk}\footnote{Nodewalks are much improved in v2.0, so some syntax and keys are different than in v1.0!}&\indexdef{value of=compat>1.0-nodewalk}\\ + \keyname{for}&\index{for step=\index{group}}&\indexdef{value of=compat>1.0-for}\\ + \keyname{for all next}&\index{for step=\index{following siblings}}&\indexdef{value of=compat>1.0-forall}\\ + \keyname{for all previous}&\index{for step=\index{preceding siblings}}&\indexdef{value of=compat>1.0-forall}\\ + \keyname{for ancestors'}&\index{for step=\index{current and ancestors}}&\indexdef{value of=compat>1.0-ancestors}\\ + (\keyname{for}) \keyname{linear next}&(\index{for step}) \index{next node}&\indexdef{value of=compat>1.0-linear}\\ + (\keyname{for}) \keyname{linear previous}&(\index{for step}) \index{previous node}&\indexdef{value of=compat>1.0-linear}\\ + \keyname{triangle}&\index{roof} (library \reflibrary{linguistics})&\indexdef{value of=compat>1.0-triangle}\\ + \keyname{/tikz/fit to tree}&\index{fit to}\keyname{=}\index{tree}\footnote{The v1.0 key \keyname{/tikz/fit to tree} also set \keyname{inner sep=0}; the v2.0 key \index{fit to} does not do that.}&\indexdef{value of=compat>1.0-fittotree}\\ \keyname{begin forest}, \keyname{end forest}&none (use \index{style>stages})&\index{1.0-stages}\\ \keyname{end forest}, \keyname{end forest}&none (use \index{style>stages})&\index{1.0-stages}\\ \end{tabularx} @@ -5543,17 +6598,6 @@ First of all, the list of all \index{compat} keys for backward compatibility, an \end{description} -\paragraph{Acknowledgements} -This package has turned out to be much more successful and widespread than I could have ever -imagined and I want to thank all the users for the trust. Many of you have also contributed to the -package in some way: by providing comments and ideas, sending patches, reporting bugs and so on. To -you, I'm doubly grateful! I will not even try to list you all here, as the list is getting too long -for me to maintain, but I do want to mention one person, a member of the friendly community at the -excellent and indispensable \href{http://tex.stackexchange.com}{\TeX\ -- \LaTeX\ Stack Exchange} and -the author of the very first \foRest;-based package, -\href{http://ctan.org/pkg/prooftrees}{Prooftrees}: without |cfr|'s uncountable questions, answers, -bug reports and ideas, \foRest; would be a much poorer package indeed. - \subsection{Known bugs} \label{sec:bugs} @@ -5585,7 +6629,7 @@ If you notice one, please let me know. In the following example, the R--B edge crosses the AAA node, although \index{ignore edge} is set to the default |false|. -\begin{forestexample}[index={calign,{value=calign>first},align,{value=align>center},base,{value=base>bottom}}] +\begin{forestexample}[index={calign,{value of=calign>first},align,{value of=align>center},base,{value of=base>bottom}}] \begin{forest} calign=first [R[AAAAAAAAAA\\AAAAAAAAAA\\AAAAAAAAAA,align=center,base=bottom][B]] @@ -5595,7 +6639,7 @@ This happens because s-distances between the adjacent children are computed before child alignment (which is obviously the correct order in the general case), but child alignment non-linearly influences the edges. Observe that the with a different value of \index{calign}, the problem does not arise. -\begin{forestexample}[index={calign,{value=calign>last},align,{value=align>center},base,{value=base>bottom}}] +\begin{forestexample}[index={calign,{value of=calign>last},align,{value of=align>center},base,{value of=base>bottom}}] \begin{forest} calign=last [R[AAAAAAAAAA\\AAAAAAAAAA\\AAAAAAAAAA,align=center,base=bottom][B]] @@ -5636,6 +6680,20 @@ Obviously, both examples also create the situation of an edge crossing some sibl Again, I don't think anything sensible can be done about this, in general. +\subsection{Acknowledgements} + +This package has turned out to be much more successful and widespread than I could have ever +imagined and I want to thank all the users for the trust. Many of you have also contributed to the +package in some way: by providing comments and ideas, sending patches, reporting bugs and so on. To +you, I'm doubly grateful! I will not even try to list you all here, as the list is getting too long +for me to maintain, but I do want to mention one person, a member of the friendly community at the +excellent and indispensable \href{http://tex.stackexchange.com}{\TeX\ -- \LaTeX\ Stack Exchange} and +the author of the very first \foRest;-based package, +\href{http://ctan.org/pkg/prooftrees}{Prooftrees}: without |cfr|'s uncountable questions, answers, +bug reports and ideas, \foRest; would be a much poorer package indeed. + + + \addcontentsline{toc}{section}{References} \bibliography{tex} \bibliographystyle{plain} @@ -5645,7 +6703,13 @@ Again, I don't think anything sensible can be done about this, in general. \addcontentsline{toc}{section}{\indexname} \addtocontents{toc}{\protect\setbox0=\protect\vbox{\protect\iffalse}\protect\fi} \PrintIndex -\addtocontents{toc}{\protect\iffalse{\protect\fi}} +%\addtocontents{toc}{\protect\iffalse{\protect\fi}} +%http://tex.stackexchange.com/questions/10291/addtocontents-at-end-of-document-not-getting-written-to-toc-file +\makeatletter +\write\@auxout{\noexpand\@writefile{toc}{\noexpand\iffalse{\noexpand\fi}}} +\makeatother + + \end{document} diff --git a/Master/texmf-dist/doc/latex/forest/forest.pdf b/Master/texmf-dist/doc/latex/forest/forest.pdf Binary files differindex c7db075188d..11d3d857dd2 100644 --- a/Master/texmf-dist/doc/latex/forest/forest.pdf +++ b/Master/texmf-dist/doc/latex/forest/forest.pdf diff --git a/Master/texmf-dist/source/latex/forest/forest-index.dtx b/Master/texmf-dist/source/latex/forest/forest-index.dtx index e7993c114a8..6ffa1d137be 100644 --- a/Master/texmf-dist/source/latex/forest/forest-index.dtx +++ b/Master/texmf-dist/source/latex/forest/forest-index.dtx @@ -1,9 +1,9 @@ -% \CheckSum{561} +% \CheckSum{756} % \iffalse meta-comment % forest-index.dtx %% `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 %% @@ -150,11 +150,14 @@ {\let\forestindex@resolvekey\forestindex@resolvekey@long} {\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}} \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} @@ -181,9 +184,10 @@ % \begin{macrocode} \def\forestindex@index#1#2#3{% % \end{macrocode} -% Partition the index keylist into single keys. +% Partition the index keylist into single keys. And put it all in a group: the +% persistent stuff is saved globally. % \begin{macrocode} - \forcsvlist{\forestindex@forkey{#1}{#2}}{#3}% + {\forcsvlist{\forestindex@forkey{#1}{#2}}{#3}}% } \def\forestindex@forkey#1#2#3{% % \end{macrocode} @@ -191,11 +195,23 @@ % \begin{macrocode} \forestindex@resolvekey{#3}% % \end{macrocode} -% Call the central processing command, style |@index|. See how -% \indexex{process args} is used to expand (once) the last argument. +% Manipulate arguments a bit, so that we can use our quick-and-dirty one-arg +% memoization. % \begin{macrocode} - \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 } +% \end{macrocode} +% Call the central processing command, style |@index|. See how +% \indexex{handler>process} is used to expand (once) the last argument. +% \begin{macrocode} +\def\forestindex@index@#1{\forestset{@index/.process={__o}#1}} \forestset{ % \end{macrocode} % \subsubsection*{Declarations} @@ -206,6 +222,7 @@ % \begin{macrocode} declare boolean register=print, declare boolean register=index, + declare boolean register=short, short, % \end{macrocode} % Options |name|, |content|, |key| and |argument| hold info about the % current entry. We need to declare only the latter two, the former @@ -307,11 +324,15 @@ 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'={ % \end{macrocode} +% Don't memoize if the key is of an unknown category. +% \begin{macrocode} + if strequal/.process={O}{!root.name}{@unknown}{TeX=\global\forest@memoizing@ok@false}{}, +% \end{macrocode} % Option |print_form| is what will be typeset in the text. Option % |index_key| is the key that will be used for sorting the % index. Option |index_form| is what will be typeset in the index. All @@ -325,7 +346,7 @@ index form/.option=key, }, % \end{macrocode} -% Below, \indexex{node key>on invalid} is set to \indexex{value=on invalid>fake} at four points. +% Below, \indexex{node key>on invalid} is set to \indexex{value of=on invalid>fake} at four points. % This is so we won't get in trouble when |\indexset|ting the % categories: when the category formatting code will try to step into % the child, it will fail as the child does not exist when |\indexset| @@ -345,7 +366,7 @@ % Ancestors are walked in the \indexex{reverse} order (top down). At % every node, the saved configuration is executed (if it exists). % \begin{macrocode} - for reverse={ancestors}{on invalid={fake}{@@index/\forestoption{name}/.try}}, + for reverse={current and ancestors}{on invalid={fake}{@@index/\forestoption{name}/.try}}, % \end{macrocode} % We don't execute the saved configuration for definitions, as % definitions are where the configuration is set. @@ -377,17 +398,14 @@ % \FoRest; points: % \begin{enumerate*}[(i)] % \item the generic conditional \indexex{if}, -% \item handler \index[print form=wrap 2 pgfmath args]{wrap $n$ pgfmath args}, -% \item long nodewalk in the relative node name, which is an argument -% to a |pgfmath| option function, automatically created for the -% |index@hypertarget| option declared in this package. +% \item handler \index{handler>process}, % \end{enumerate*} % \begin{macrocode} - 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}, }, }{}, % \end{macrocode} @@ -441,15 +459,15 @@ }, }, temptoksa={}, - result={}, + result'={}, if n children=0{tempboola}{not tempboola}, where index form={}{}{ % \end{macrocode} -% If the (outer) current node has no children, make it the hypertarget -% that the definitions in text will point to. +% Create the hypertarget that the definitions in text and other index entries +% will point to. % \begin{macrocode} - if tempboola={temptoksd/.expanded={\noexpand\protect\noexpand\hypertarget{% - \forestoption{index@hypertarget}}{}}}{temptoksd={}}, + temptoksd/.expanded={\noexpand\protect\noexpand\hypertarget{% + \forestoption{index@hypertarget}}{}}, % \end{macrocode} % Add the (inner) current node to the index entry of the (outer) current node. % \begin{macrocode} @@ -467,7 +485,7 @@ % Do the actual indexing. % \begin{macrocode} 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 }{}, @@ -486,7 +504,7 @@ % \end{macrocode} % Typeset the entry in the text. % \begin{macrocode} - for first leaf'={TeX={\forestoption{print form}}}, + for first leaf'={TeX and memoize/.expanded={\forestoption{print form}}}, endgroup, }{}, } @@ -519,8 +537,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}, }, } }, @@ -549,31 +567,33 @@ % \end{macrocode} % Don't save entries of unknown category. % \begin{macrocode} - if={strequal(name("!root"),"@unknown")}{}{ + if strequal/.process={O}{!root.name}{@unknown}{}{ % \end{macrocode} % Don't save if nothing is set. % \begin{macrocode} 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}}}% }% }, }, + }, % \end{macrocode} % Save the full form of the key in the auxiliary file. Obviously, do % it only for subentries. The full form contains whatever arguments % were given to the non-last component. % \begin{macrocode} - 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}}}% + }% + }{}% } } - }, + } } % \end{macrocode} % Load settings from the auxiliary file into the global style. Warn @@ -584,7 +604,9 @@ \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! @@ -665,8 +687,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}, % \end{macrocode} % Use this style in |..._format| keylists if you want the index @@ -720,9 +742,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}}, }, } % \end{macrocode} @@ -744,6 +767,10 @@ \long\def\pgfkeysglobalsetvalue#1#2{% \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}}}, +} % \end{macrocode} % Begin and end group, \foRest;-style: % \begin{macrocode} @@ -752,7 +779,92 @@ endgroup/.code={\endgroup}, } % \end{macrocode} -% +% +% \subsubsection{Memoize} +% +% Quick and dirty memoization. Single argument macros only. Does not support nesting. +% +% \begin{macrocode} +\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{% +% \end{macrocode} +% The following two |\def|s remove one level of hash-doubling from the +% arguments, introduced by |\write|. +% \begin{macrocode} + \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}% +} +% \end{macrocode} +% Commenting the following line turns off memoization. +% \begin{macrocode} +\forest@memoize\forestindex@index@ +% \end{macrocode} +% % \subsubsection*{Initialize} % % Declare category ``@unknown''. diff --git a/Master/texmf-dist/source/latex/forest/forest-libs.dtx b/Master/texmf-dist/source/latex/forest/forest-libs.dtx index 2cb32097a52..360d954afa1 100644 --- a/Master/texmf-dist/source/latex/forest/forest-libs.dtx +++ b/Master/texmf-dist/source/latex/forest/forest-libs.dtx @@ -1,9 +1,9 @@ -% \CheckSum{235} +% \CheckSum{236} % \iffalse meta-comment % forest-libs.dtx %% `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 %% @@ -70,13 +70,12 @@ } % \end{macrocode} % -% There's no linguistics without c-command\footnote{The definition of c-command is as follows: a node c-commands its siblings and their subtrees.} \dots +% There's no linguistics without c-command\footnote{The definition of c-command is as follows: a node c-commands its siblings and their descendants.} \dots % \begin{syntax} % \indexitem{step>c-commanded} Visit all the nodes c-commanded by the current node. % \indexitem{step>c-commanders} Visit all the c-commanders of the current node, starting from the closest. % % \begin{forestexample}[tree bin=minipage,index={branch',c-commanded}] -% ``manual'' c-command:\\[1ex] % \begin{forest} % [VP % [DP[John]] @@ -190,7 +189,7 @@ % xlist/.style={ % phantom, % for children={no edge,replace by={[,append, -% delay={content/.wrap pgfmath arg={\@alph{##1}.}{n()+#1}} +% delay={content/.wrap pgfmath arg={\csname @alph\endcsname{##1}.}{n()+#1}} % ]}} % }, % xlist/.default=0 @@ -239,7 +238,7 @@ for tree'={ TeX={[% % \end{macrocode} -% Complication: \index{content format} must be expanded in advance, to correctly process tabular environments implicitely loaded by \index{align}|=|\index{value=align>center}, which is the default in this library. (Not that one would want a multiline output in the bracket representation, but it's better than crashing.) +% Complication: \index{content format} must be expanded in advance, to correctly process tabular environments implicitely loaded by \index{align}|=|\index{value of=align>center}, which is the default in this library. (Not that one would want a multiline output in the bracket representation, but it's better than crashing.) % \begin{macrocode} \edef\forestdrawbracketscontentformat{\foresteoption{content format}}% }, @@ -374,29 +373,28 @@ %\fi % \librarysection{edges} % \begin{macrocode} -\ProvidesForestLibrary{edges}[2015/11/14 v0.1] +\ProvidesForestLibrary{edges}[2016/12/05 v0.1.1] % \end{macrocode} % % \begin{syntax} % -% \indexitem{node key>forked edge} +% \indexitem{node key>forked edge'} % % Sets a forked edge to the current node. Arbitrary growth direction and node rotation are % supported. % -% Using this key does \emph{not} change the current values of \index{option>parent anchor} and -% \index{option>child anchor}. -% -% \indexitem{node key>forked edges} +% \indexitem{node key>forked edge} % -% Sets forked edges to the entire (sub)tree rooted in the current node. Arbitrary growth -% direction and node rotation are supported. +% Like \index{forked edge'}, but it also sets \index{option>parent anchor} and \index{option>child +% anchor} to the likely values of \index{anchor>children} and \index{anchor>parent}, respectively. % -% \index{option>parent anchor} and \index{option>child anchor} are set to \index{anchor>children} and -% \index{anchor>parent}, repectively. +% \indexitem(tree){node key>forked edges}|=|\meta{nodewalk} % -% \indexitem{option>fork sep} The \index{forest cs>l}-distance between the parent anchor and the -% fork. +% Invokes \index{forked edge} for all nodes in the \meta{nodewalk}, by default the entire (sub)tree +% rooted in the current node. +% +% \indexitem{option>fork sep} The \index{forest cs>l}-distance between the parent anchor and the +% fork. % % \end{syntax} % @@ -421,19 +419,23 @@ % \end{forest} % \end{forestexample} % -% See how \indexex{anchor>parent anchor} and \indexex{anchor>parent anchor} are used in the -% definition of |forked_edge| to easily take care of arbitrary \index{grow} and \index{rotate}. +% See how growth direction based anchors \indexex{anchor>children} and \indexex{anchor>parent} are +% used in the definition below to easily take care of arbitrary \index{grow} and +% \index{rotate}. % \begin{macrocode} \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, } % \end{macrocode} % @@ -481,14 +483,14 @@ 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/source/latex/forest/forest.dtx b/Master/texmf-dist/source/latex/forest/forest.dtx index 0c5c72dc314..1416caca536 100644 --- a/Master/texmf-dist/source/latex/forest/forest.dtx +++ b/Master/texmf-dist/source/latex/forest/forest.dtx @@ -1,9 +1,9 @@ -% \CheckSum{12887} +% \CheckSum{16573} % \iffalse meta-comment % forest.dtx %% `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 %% @@ -83,7 +83,7 @@ % % \section{Identification} % \begin{macrocode} -\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} @@ -97,8 +97,74 @@ \RequirePackage{environ} \RequirePackage{xparse} -% \usepackage[trace]{trace-pgfkeys} - +\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}}% + } % \end{macrocode} % % |/forest| is the root of the key hierarchy. @@ -114,12 +180,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{% @@ -127,10 +196,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 @@ -141,10 +211,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} % \end{macrocode} % \section{Patches} @@ -184,13 +261,36 @@ % % \section{Utilities} % +% This is handy. +% \begin{macrocode} +\def\forest@empty{} +% \end{macrocode} +% % Escaping |\if|s. % \begin{macrocode} \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} % \end{macrocode} -% +% +% \begin{macrocode} +\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}% +} +% \end{macrocode} +% % A factory for creating |\...loop...| macros. % \begin{macrocode} \def\newloop#1{% @@ -508,6 +608,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}}% }% }{}% @@ -559,6 +660,851 @@ \fi }% } +\forestset{ + show register/.code={% + \forestrget{#1}\foresttemp + \typeout{Forest register "#1"=\expandafter\detokenize\expandafter{\foresttemp}}% + }, +} +% \end{macrocode} +% \subsection{Arrays} +% +% \begin{macrocode} +\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}).}{}}% +% \end{macrocode} +% Define array macros. For speed, we define most of them to be ``direct'', i.e.\ cointain the resolved control sequences specific to this array. +% \begin{macrocode} +\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% + }% +% \end{macrocode} +% I would love to define these only generically, as they will not be called often, but they need to be expandable. Argh. +% right? +% \begin{lstlisting} +% \def\arrayvalues{% <-- \csedef{#1values} +% \expandafter\expandafter\expandafter\arrayvaluesfromrange %\arrayvaluesfromrange <-- \expandonce{\csname#1valuesfromrange\endcsname} +% \expandafter\expandafter\expandafter{% +% \expandafter\the +% \expandafter\arrayM %\arrayM <-- \expandonce{\csname#1M\endcsname}% +% \expandafter}% +% \expandafter{% +% \the\arrayN %\arrayN <-- \expandonce{\csname#1N\endcsname}% +% }% +% }% +% \end{lstlisting} +% \begin{macrocode} + \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}}% + }% +% \end{macrocode} +% \begin{lstlisting} +% \def\arrayvaluesfromrange##1##2{% ##1/##2 = lower/upper bounds (we receive them expanded) <-- \csedef{#1vuesfromrange} +% \ifnum##1<##2 +% {\expandafter\expandonce\expandafter{\csname#1##1\endcsname}}% here we add braces (for the general case, we might want an arbitrary prefix&suffix) +% \expandafter\@escapeif\expandafter{\expandafter\arrayvaluesfromrange % <-- \expandonce{\csname#1valuesfromrange\endcsname}% +% \expandafter{\number\numexpr##1+1}{##2}}% +% \fi +% }% +% \end{lstlisting} +% As we need this to be expandable, we cannot check the range within the macro. You need to to this on your own using |...checkrange| defined above. +% \begin{macrocode} + \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 + }% +% \end{macrocode} +% Puts all items until |\forest@eov| into the array. After that is done, execute |\forest@topextend@next|. This code is difficult and not run often, so it doesn't need specialized control sequences. +% \begin{macrocode} + \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@ +% \end{macrocode} +% +% +% \subsection{Testing for numbers and dimensions} +% \label{sec:is-count-or-dimen} +% +% Test if the argument is an integer (only base 10) that can be assigned to a \TeX\ count register. +% This is supposed to be a fast, not complete test, as anything not recognized as an integer will be +% passed on to |pgfmath| (by the code that uses these macros). +% +% We support |+|s, |-|s and spaces before the number. We don't support count registers. +% +% Dillema? Should |0abc| be interpreted as \TeX\ style (decimal) or PGF style (octal)? We go for +% \TeX\ style. +% +% The return value will hide in \TeX-style |\if|-macro |\forest@isnum| and counter |\forest@isnum@count|. +% +% \begin{macrocode} +\def\forest@eon{ } +\newif\ifforest@isnum@minus +\newif\ifforest@isnum +\def\forest@isnum#1{% + \forest@isnum@minusfalse + \let\forest@isnum@next\forest@isnum@finish +% \end{macrocode} +% Expand in advance, like pgfmath does. +% \begin{macrocode} + \edef\forest@isnum@temp{#1}% +% \end{macrocode} +% Add two end-of-value markers. The first one might be eaten by count assignment: that's why there +% are two and they expand to a space. +% \begin{macrocode} + \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} +% \end{macrocode} +% Test for three special characters: |-|, |+|, and space. +% \begin{macrocode} +\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 +} +% \end{macrocode} +% Eat |+| and |-|. +% \begin{macrocode} +\def\forest@isnum@c#1{\forest@isnum@a}% +% \end{macrocode} +% Eat the space! +% \begin{macrocode} +\def\forest@isnum@s#1{\forest@isnum@a#1}% +\newcount\forest@isnum@count +% \end{macrocode} +% Check for |0|. Why? If we have one, we know that the initial argument started with a number, so +% we have a chance that it is a number even if our assignment will yield $0$. If we have no |0| and the assignment yields $0$, we know we don't have a number. +% \begin{macrocode} +\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 +} +% \end{macrocode} +% This is the end of testing for an integer. If we have left-over stuff (|#1|), this was not a number. +% \begin{macrocode} +\def\forest@isnum@finish#1\forest@END{% + \ifx\forest@isnum@token\forest@eon + \else + \forest@isnumfalse + \fi +} +% \end{macrocode} +% +% Is it a dimension? We support all \TeX's units but |true| units. Also supported are unitless +% dimensions (i.e.\ decimal numbers), which are interpreted as |pt|s, as in pgfmath. +% +% The return value will hide in \TeX-style |\if|-macro |\forest@isdim| and counter |\forest@isdim@dimen|. +% +% \begin{macrocode} +\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}% +% \end{macrocode} +% 4 end-of-value markers (|forest@eon|): one can be eaten by number (after the dot), two by a non-existing unit. +% \begin{macrocode} + \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 +% \end{macrocode} +% No number, no dot, so not a dimension. +% \begin{macrocode} + \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% +} +% \end{macrocode} +% Nothing else should be defined in |\forest@unit@| namespace. +% \begin{macrocode} +\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 +} +% \end{macrocode} +% +% +% \subsection{forestmath} +% +% We imitate |pgfmath| a lot, but we remember the type of the result so that we can use \TeX's +% primitives when possible. +% \begin{macrocode} +\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 +% \end{macrocode} +% |\forest@tryprocess| takes three ``arguments''. The first is a forestmath expression, delimited +% by |\forest@spacegen|: if it starts with a |>|, we take it to be a |.process| expression, evaluate +% it using |\forest@process|, and execute the second argument; it it doesn't, we execute the third +% argument. +% \begin{macrocode} +\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} +% \end{macrocode} +% Forestmath versions of pgfmath macros. They accept process and pgfmath expressions, as described +% above. In the case of a pgfmath expression, they use |\forest@isnum| and |\forest@isdim| for to +% see if they can avoid pgfmath evaluation. (These checks are generally faster than pgfmath's fast +% track.) +% \begin{macrocode} +\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}% + }% +} +% \end{macrocode} +% Evaluates |#1| to a boolean: if true execute |#2|, otherwise |#3|. |#2| and |#3| are \TeX\ code. +% Includes a shortcut for some common values. +% \begin{macrocode} +\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}} +% \end{macrocode} +% These macros expandably convert a num(n)/dim(d)/unitless dim(P) to a num(n)/dim(d)/unitless +% dim(P). +% \begin{macrocode} +\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}} +% \end{macrocode} +% These defer conversion (see aggregates). +% \begin{macrocode} +\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}} +% \end{macrocode} +% Sets |\pgfmathresulttype| to the type of |#1|. +% \begin{macrocode} +\def\forestmathsettypefrom#1{% + \forest@isnumdim{% + \let\forestmathresulttype\forest@result@type@numexpr + }{% + \let\forestmathresulttype\forest@result@type@dimexpr + }{% + \let\forestmathresulttype\forest@result@type@pgfmath + }% +} +% \end{macrocode} +% The following functions expect numbers or (bare or specified) dimensions as their parameters. The +% version ending in |@| should get the argument type as its first argument; the version without |@| +% uses |\forestmathresulttype|. The result type doesn't need to be changed, obviously. +% \begin{macrocode} +\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 +} +% \end{macrocode} +% The return type of |forestmathdivide| is the type of the dividend. So, |n| and |d| type can only +% be divided by integers; as |\numexpr| and |\dimexpr| are used, the result is rounded. +% \begin{macrocode} +\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 +} +% \end{macrocode} +% Booleans. +% \begin{macrocode} +\def\forestmathtrue{% + \def\forestmathresult{1}% + \let\forestmathresulttype\forestmathtype@count} +\def\forestmathfalse{% + \def\forestmathresult{0}% + \let\forestmathresulttype\forestmathtype@count} +% \end{macrocode} +% Comparisons. |\pdfstrcmp| is used to compare text (types |t| and |T|); note that it expands its +% arguments. |<| and |>| comparison of generic type obviously makes no sense; |=| comparison is +% done using |\ifx|: this is also the reason why these macros are not fully expandable, as we need +% to |\def| the arguments to |\ifx|. +% +% Low level |<|. +% \begin{macrocode} +\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 +% \end{macrocode} +% Low level |=|. +% \begin{macrocode} +\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} +% \end{macrocode} +% High level |<|, |>| and |=|. +% \begin{macrocode} +\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} +% \end{macrocode} +% Min and max. The complication here is that for numeric/dimension types, we want the empty value to +% signal ``no argument'', i.e.\ the other argument should be the result; this is used in +% aggregates. (For text types, the empty value is obviously the lesser one.) The arguments are expanded. +% \begin{macrocode} +\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}% +} % \end{macrocode} % % \subsection{Sorting} @@ -1258,30 +2204,29 @@ % Macros for retrieving/setting node options of the current node. % \begin{macrocode} % 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\forestocslet#1#2{% +% \edef\forest@marshal{% +% \noexpand\pgfkeyslet{/forest/@node/\forest@cn/#1}{\expandonce{\csname#2\endcsname}}% +% }\forest@marshal +% } +\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}% } % \end{macrocode} % User macros for retrieving node options of the current node. @@ -1291,24 +2236,21 @@ % \end{macrocode} % Macros for retrieving node options of a node given by its id. % \begin{macrocode} -\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\forestOcslet#1#2#3{% +% \edef\forest@marshal{% +% \noexpand\pgfkeyslet{/forest/@node/#1/#2}{\expandonce{\csname#3\endcsname}}% +% }\forest@marshal +% } +\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}}% @@ -1322,8 +2264,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 @@ -1338,36 +2281,67 @@ \forestoget{#2}\forestoption@temp \forestolet{#1}\forestoption@temp} % \end{macrocode} +% Macros for retrieving node options given by \meta{relative node name}|.|\meta{option}. +% \begin{macrocode} +\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% +} +% \end{macrocode} % Macros for retrieving/setting registers. % \begin{macrocode} % 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\forestrcslet#1#2{% +% \edef\forest@marshal{% +% \noexpand\pgfkeyslet{/forest/@node/register/#1}{\expandonce{\csname#2\endcsname}}% +% }\forest@marshal +% } +\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}% } % \end{macrocode} % User macros for retrieving node options of the current node. @@ -1946,7 +2920,12 @@ % \begin{macrocode} \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 @@ -1968,12 +2947,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 @@ -2003,9 +2982,9 @@ % Recurse through the tree. If a circularity is detected, mark it with |*| and stop recursion. % \begin{macrocode} \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}% @@ -2013,6 +2992,9 @@ \eappto\forest@temp@message{%[ ]}% } +\def\forestdebugtypeouttreenodeinfo{\forest@cn} +\def\forestdebugtypeouttreesprefix{} +\def\forestdebugtypeouttreessuffix{} % \end{macrocode} % % @@ -2104,6 +3086,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 @@ -2133,25 +3116,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}% @@ -2208,37 +3210,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}% @@ -2279,33 +3300,33 @@ \pgfkeyssetvalue{#1'*/option@name}{#3}% \pgfkeyssetvalue{#1':/option@name}{#3}% } +% \end{macrocode} +% Nothing else should be defined in this namespace. +% \begin{macrocode} \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{ @@ -2319,35 +3340,44 @@ \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 }, +% \end{macrocode} +% +% \section{Handlers} +% +% \begin{macrocode} /handlers/.restore default value/.code={% \edef\forest@handlers@currentpath{\pgfkeyscurrentpath}% \pgfkeysgetvalue{\pgfkeyscurrentpath/option@name}\forest@currentoptionname @@ -2367,17 +3397,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 @@ -2385,8 +3420,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 @@ -2409,19 +3444,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 @@ -2457,103 +3489,541 @@ \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 +% \end{macrocode} +% +% \subsection{.process} +% +% \begin{macrocode} +\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@ +% \end{macrocode} +% Processing instruction need not (but may) be enclosed in braces. +% \begin{macrocode} +\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 +} +% \end{macrocode} +% Debugging and error messages. +% \begin{macrocode} +\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.}{}% +} +% \end{macrocode} +% Define the definer of processors. First, deal with the catcode of the instruction char. +% \begin{macrocode} +\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@@ +} +% \end{macrocode} +% If |#1| is non-empty, the processor accepts the optional numeric argument: |#1| is the default. +% \begin{macrocode} +\def\forest@def@processor@@#1{% + \ifstrempty{#1}{% + \forest@def@processor@@non + }{% + \def\forest@def@processor@@default@n{#1}% + \forest@def@processor@@n + }% +} +% \end{macrocode} +% We need |\relax| below because the next instruction character might get expanded when assigning the optional numerical argument which is not there. +% +% No optional n: +% \begin{macrocode} +\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 + }% +} +% \end{macrocode} +% Optional n: |*| after the given default means that the operation should be repeated n times. +% \begin{macrocode} +\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 +} +% \end{macrocode} +% A helper macro which puts the optional numeric argument into count |\forest@process@n| (default being |#1|) and then executes control sequence |#2|. +% \begin{macrocode} +\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@ +} +% \end{macrocode} +% +% Definitions of processing instructions. Processors should be defined using |\forest@def@processor|. If they take arguments: yes, they follow, but they were scanned in |\forest@process@catregime|. Processors should manipulate arrays |\forest@process@left@| and |\forest@process@right|. They should set |\def\forestmathresulttype| to |_| not defined, |n| number, |d| dimension, |P| pgfmath or |t| text. +% \begin{macrocode} +\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 +} +% \end{macrocode} +% Expansions: +% \begin{macrocode} +\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 +} +% \end{macrocode} +% Access to \foRest; data. +% \begin{macrocode} +\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 +} +% \end{macrocode} +% The following processors muck about with the argument / result list. +% \begin{macrocode} +\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} +% \end{macrocode} +% Save last |n| arguments from the left side into a special place. |s| deletes them from the left side, |S| keeps them there as well. +% \begin{macrocode} +\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 +} +% \end{macrocode} +% Load |n| arguments from the end of the special place to the left side. If $n=0$, load the entire special place. |l| deletes the args from the special place, |L| keeps them there as well. +% \begin{macrocode} +\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}% +} +\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 +} +% \end{macrocode} +% Boolean operations: +% \begin{macrocode} +\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 +} +% \end{macrocode} +% Comparisons. They automatically determine the type (number, dimen, other) of the arguments, by checking what the last processing instruction was. +% \begin{macrocode} +\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 +} +% \end{macrocode} +% Various. +% \begin{macrocode} +\forest@def@processor{r}{}{}{% reverse keylist + \forest@process@right@bottompop\forest@temp + \expandafter\forest@processor@r@\expandafter{\forest@temp}% } -\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@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{,}% + }% } % \end{macrocode} % @@ -2565,14 +4035,13 @@ } \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}% @@ -2643,6 +4112,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 @@ -2667,24 +4137,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}% @@ -2741,36 +4228,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}% @@ -2814,16 +4318,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}}, @@ -2837,6 +4338,7 @@ }, }% \pgfkeyssetvalue{#1/option@name}{#3}% + \pgfkeyslet{#1/@type}\forestmathtype@count % for .process & co \pgfmathdeclarefunction{#4}{1}{\forest@pgfmathhelper@register@count{##1}{#3}}% } \forestset{ @@ -3010,12 +4512,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{}% @@ -3213,7 +4720,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}, @@ -3269,7 +4776,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} @@ -3299,33 +4806,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}, }{}% }% @@ -3335,39 +4840,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={% @@ -3478,48 +4990,174 @@ \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}% + }% + }\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 +} +% \end{macrocode} +% Define particular aggregate functions. +% \begin{macrocode} +\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@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}% + }% +} +\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}% +} +% \end{macrocode} +% Actual computation. +% \begin{macrocode} +\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 } % \end{macrocode} % \subsubsection{\texttt{pgfmath} extensions} @@ -3539,28 +5177,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? @@ -3568,7 +5210,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 @@ -3617,10 +5259,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 }% } @@ -3630,8 +5272,7 @@ \ifnum\forest@cn=0 \def\pgfmathresult{0}% \else - \forestoget{#2}\forest@temp - \pgfmathtruncatemacro\pgfmathresult{\forest@temp}% + \forestoget{#2}\pgfmathresult \fi }% } @@ -3679,21 +5320,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 } @@ -3713,25 +5363,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 } @@ -3740,6 +5392,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 @@ -3844,6 +5501,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 }, } @@ -3856,7 +5515,7 @@ % |\forest@forstepwrapper| is defined so that it can be changed by |compat| to create unfailable spatial propagators from v1.0. % \begin{macrocode} \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 @@ -3868,7 +5527,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}{}} % \end{macrocode} % Define long-form single-step walks. @@ -3917,21 +5580,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 @@ -3940,9 +5603,23 @@ \fi \safeloop \edef\forest@cn{\forest@node@linearpreviousid}% - \forestoget{tier}\forest@nodewalk@tier - \unless\ifx\forest@nodewalk@tier\forest@nodewalk@giventier - \saferepeat + \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}{% @@ -3953,7 +5630,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}{% @@ -3963,19 +5640,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 }, @@ -3992,45 +5669,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 @@ -4050,23 +5717,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, @@ -4082,7 +5751,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 @@ -4097,7 +5766,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=% @@ -4106,12 +5775,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{% @@ -4121,38 +5791,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 }, @@ -4205,7 +5891,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={% @@ -4223,6 +5911,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}% @@ -4313,12 +6016,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@@} @@ -4366,7 +6064,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 @@ -4454,7 +6152,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}% @@ -4679,7 +6377,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}% @@ -4687,7 +6385,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}% @@ -4695,8 +6393,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 @@ -4711,7 +6408,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}% @@ -4719,7 +6416,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}% @@ -4727,7 +6424,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}% @@ -4736,7 +6433,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}% @@ -4744,7 +6441,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}% @@ -4752,7 +6449,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}% @@ -4760,7 +6457,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}% @@ -4768,7 +6465,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}% @@ -4776,13 +6473,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}}, @@ -4867,7 +6577,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 @@ -4884,7 +6600,7 @@ } \forestset{ save and restore register/.code 2 args={% - \forest@saveandrestoreregister{filter@ed}{% + \forest@saveandrestoreregister{#1}{% \pgfkeysalso{#2}% }% }, @@ -4995,21 +6711,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 @@ -5025,10 +6736,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{% @@ -5056,29 +6766,56 @@ \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 } +% \end{macrocode} +% Usage: |\forest@nodesort@cmp|\meta{first}\meta{second}. Fully expandable. Return |<|, |=| or |>|, as required by |\forest@sort|. +% \begin{macrocode} +\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}% } @@ -5141,9 +6878,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{% @@ -5732,7 +7476,7 @@ \def\forest@pack@pgfpoint@childsposition#1{% {% \pgftransformreset - \pgftransformrotate{\forestove{grow}}% + \forest@pgfqtransformrotate{\forestove{grow}}% \forest@fornode{#1}{% \pgfpointtransformed{\pgfqpoint{\forestove{l}}{\forestove{s}}}% }% @@ -5745,7 +7489,7 @@ \def\forest@pack@pgfpoint@positioningrow#1{% {% \pgftransformreset - \pgftransformrotate{#1}% + \forest@pgfqtransformrotate{#1}% \pgfpointtransformed{\pgfqpoint{\forestove{l}}{\forestove{s}}}% }% } @@ -5766,7 +7510,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}% @@ -5775,7 +7519,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 }% @@ -5793,7 +7537,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}% @@ -5809,7 +7553,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 }% @@ -5823,6 +7567,10 @@ % angles between node anchors; the version |fixes_edge_angles| calculates the angles between the % node edges. % \begin{macrocode} +\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}}}% @@ -5833,45 +7581,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}% @@ -5897,64 +7684,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}% @@ -6030,7 +7876,7 @@ % \begin{macrocode} \pgfgettransform\forest@temp@transform \pgftransformreset - \pgftransformrotate{\forestove{grow}}% + \forest@pgfqtransformrotate{\forestove{grow}}% % \end{macrocode} % Get the child's (cached) edge, translate it by the child's position, % and add it to the path holding all edges. Also add the edge from parent to the child to the path. @@ -6662,8 +8508,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 @@ -6835,7 +8685,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 @@ -7237,6 +9087,10 @@ \let\forest@previous@py\forest@py } % \end{macrocode} +% Patch for speed: no need to call |\pgfmathparse| here. +% \begin{macrocode} +\patchcmd{\pgfpointintersectionoflines}{\pgfpoint}{\pgfqpoint}{}{} +% \end{macrocode} % % \subsection{Get tight edge of path} % @@ -7659,7 +9513,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 % \end{macrocode} @@ -7722,7 +9580,7 @@ }% {% \pgftransformreset - \pgftransformrotate{\forest@grow}% + \forest@pgfqtransformrotate{\forest@grow}% \forest@pgfpathtransformed\forest@gre@path }% \pgfsyssoftpath@getcurrentpath#2% @@ -7735,7 +9593,7 @@ }% {% \pgftransformreset - \pgftransformrotate{\forest@grow}% + \forest@pgfqtransformrotate{\forest@grow}% \forest@pgfpathtransformed\forest@gre@path }% \pgfsyssoftpath@getcurrentpath#2% @@ -7752,13 +9610,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% @@ -8001,7 +9859,7 @@ \def\forest@path@getboundingrectangle@ls#1#2{% {% \pgftransformreset - \pgftransformrotate{-(#2)}% + \forest@pgfqtransformrotate{-#2}% \forest@pgfpathtransformed#1% }% \pgfsyssoftpath@getcurrentpath\forest@gbr@rotatedpath @@ -8026,6 +9884,20 @@ \ifdim#2>\pgf@yb\relax\pgf@yb=#2 \fi } % \end{macrocode} +% Hack: create our own version of |pgf|'s |\pgftransformrotate| which does not call |\pgfmathparse|. Nothing really bad happens if patch fails. We're just a bit slower. +% \begin{macrocode} +\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} +% \end{macrocode} % % \section{The outer UI} % @@ -8053,10 +9925,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 @@ -8066,6 +9939,7 @@ \repeat \immediate\closeout\forest@copy@out \closein\forest@copy@in + \endgroup } \newif\ifforest@external@optimize@ \forest@external@optimize@true @@ -8137,11 +10011,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}}} @@ -8413,9 +10291,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} % \end{macrocode} @@ -8437,11 +10315,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={% @@ -8456,16 +10334,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}% @@ -8590,10 +10468,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}% @@ -8602,14 +10488,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}% @@ -8618,14 +10516,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}% @@ -8634,14 +10544,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}% @@ -8650,6 +10572,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}% +} % \end{macrocode} % The driver. The result is being passed around in |\forest@temp@anchor|. % \begin{macrocode} @@ -8688,9 +10614,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 @@ -8702,14 +10638,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'}{% @@ -8717,19 +10673,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'}% @@ -8742,18 +10716,34 @@ \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'}% +} % \end{macrocode} % This macro computes the "average" angle of |#1| and |#2| and stores in into |#3|. % The angle computed is the geometrically "closer" one. The formula is @@ -8761,30 +10751,40 @@ % \begin{macrocode} \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{} % \end{macrocode} % The first macro changes border anchor to compass anchor. The second one does this only if the node shape allows it. % \begin{macrocode} \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 @@ -8803,11 +10803,12 @@ % This macro approximates an angle (stored in |\forest@temp@anchor|) with a compass direction (stores it in the same macro). % \begin{macrocode} \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 } % \end{macrocode} % This macro forwards the resulting anchor to \TikZ;. @@ -8840,33 +10841,31 @@ % % This macro sets up |\pgf@x| and |\pgf@y| to the given anchor's coordinates, within the node's coordinate system. It works even before the node was positioned. If the anchor is empty, i.e.\ if is the implicit border anchor, we return the coordinates for the center. % \begin{macrocode} +\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}% + \forest@global@marshal } % \end{macrocode} % 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} } |