diff options
author | Karl Berry <karl@freefriends.org> | 2017-08-03 21:07:30 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2017-08-03 21:07:30 +0000 |
commit | ff587f620cc7c6d0068c33b27a8e554bce2b08fe (patch) | |
tree | 0857cebe6e2e1325bb94305516fbf9b6e27326c0 /Master/texmf-dist/tex/latex/spectralsequences/sseqkeys.code.tex | |
parent | 29d69088963132c0a036286f984331c74ac99f1a (diff) |
spectralsequences (3aug17)
git-svn-id: svn://tug.org/texlive/trunk@44942 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/latex/spectralsequences/sseqkeys.code.tex')
-rw-r--r-- | Master/texmf-dist/tex/latex/spectralsequences/sseqkeys.code.tex | 892 |
1 files changed, 612 insertions, 280 deletions
diff --git a/Master/texmf-dist/tex/latex/spectralsequences/sseqkeys.code.tex b/Master/texmf-dist/tex/latex/spectralsequences/sseqkeys.code.tex index 74667335805..a231aca7b42 100644 --- a/Master/texmf-dist/tex/latex/spectralsequences/sseqkeys.code.tex +++ b/Master/texmf-dist/tex/latex/spectralsequences/sseqkeys.code.tex @@ -1,8 +1,8 @@ %% -%% Package: spectralsequences.sty version 1.0 +%% Package: spectralsequences v1.1.0 %% Author: Hood Chatham %% Email: hood@mit.edu -%% Date: 2017-06-18 +%% Date: 2017-08-02 %% License: Latex Project Public License %% %% File: sseqkeys.code.tex @@ -12,7 +12,7 @@ %% - +% Run \pgfqkeys{directory}{keys} but for a list of directories. Helps to avoid code duplication. \def\sseq@pgfqkeysdirlist#1#2{% \sseq@temptoks{#2}% \sseq@pgfqkeysdirlist@#1,\sseq@nil @@ -27,7 +27,7 @@ % These are the things that are used outside of this section: \let\sseq@pgfkeys@error@save\pgfkeys@error \pgfkeys{/sseqpages/userstyles/.unknown/.code={\sseq@passoptionto{\sseq@sseqsetdirectory}}} -\def\sseqset#1{\pgfqkeys{/sseqpages/userstyles}{#1}} +\protected\def\sseqset#1{\pgfqkeys{/sseqpages/userstyles}{#1}} \def\sseq@sseqsetdirectory{/sseqpages/global/default} @@ -60,7 +60,7 @@ % on the first pass. Some only do things on the first pass or only do things on the second pass. % For example, shifts: shifts apply a coordinate transform on the second pass, but also need to factor into the coordinates of % classes etc which are computed at specification time not at draw time. So xshift=2 increases \sseq@x by 2 on it's first pass and -% applies a coordinate transfrom by 2cm on the second pass. +% applies a coordinate transform by 2cm on the second pass. % normal mode does the firstpass options now and saves the secondpass options in \sseq@savedoptioncode for later use. % firstpass mode does the firstpass options and throws away the secondpass options. @@ -131,24 +131,33 @@ % This is for .unknown handlers. Try same key in different directory #1. \def\sseq@passoptionto#1{\sseq@eval{\@nx\pgfqkeys{#1}{\pgfkeyscurrentname={\unexpanded\@xp{\pgfkeyscurrentvalue}}}}} +% Immediately execute a key that is either a tikz or pgf key. +% #1 -- key +% #2 -- value \def\sseq@pgfkeysdocommand#1#2{ \sseq@tempiffalse - \sseq@pgfkeysdocommand@try{/tikz/#1}{#2} - \sseq@pgfkeysdocommand@try{/pgf/#1}{#2} - % is this really an internal error? Maybe we should have failed earlier? + \sseq@pgfkeysdocommand@try{/tikz}{#1}{#2} + \sseq@pgfkeysdocommand@try{/pgf}{#1}{#2} \ifsseq@tempif\else\sseq@error@internal@nn{do-command-failed}{#1}{#2}\fi } -\def\sseq@pgfkeysdocommand@try#1#2{ +% Execute a key if \sseq@tempif is true and it is defined, if so set \sseq@tempif to false. +% These are meant to cascade. +% #1 -- directory +% #2 -- key +% #3 -- value +\def\sseq@pgfkeysdocommand@try#1#2#3{ \ifsseq@tempif\else - \pgfkeysifdefined{#1/.@cmd}{ + \pgfkeysifdefined{#1/#2/.@cmd}{ \sseq@tempiftrue - \pgfkeysgetvalue{#1/.@cmd}{\pgfkeys@code}% - \pgfkeys@code#2\pgfeov + \def\pgfkeysdefaultpath{#1/} + \edef\pgfkeyscurrentkey{#1/#2} + \pgfkeysgetvalue{#1/#2/.@cmd}{\pgfkeys@code}% + \pgfkeys@code#3\pgfeov }{ - \pgfkeysifdefined{#1}{ + \pgfkeysifdefined{#1/#2}{ \sseq@tempiftrue - \pgfkeyssetvalue{#1}{#2} + \pgfkeyssetvalue{#1/#2}{#3} }{} } \fi @@ -180,13 +189,13 @@ \@xp\pgfutil@in@\@xp-\@xp{\tikz@key}% \ifpgfutil@in@% % Ah, an arrow spec! - \sseq@add@tikzkey@to@options{\@nx\tikz@processarrows{\tikz@key}}% + \sseq@add@tikzkey@to@options{\@nx\sseq@options@secondpass{\@nx\tikz@processarrows{\tikz@key}}}% \else% % Ok, third chance: A shape! \@xp\ifx\csname pgf@sh@s@\tikz@key\endcsname\relax% \sseq@keys@unknown@error% \else% - \sseq@add@tikzkey@to@options{\def\@nx\tikz@shape{\tikz@key}}% + \sseq@add@tikzkey@to@options{\@nx\sseq@options@secondpass{\def\@nx\tikz@shape{\tikz@key}}}% \fi% \fi% }% @@ -195,8 +204,8 @@ } \def\sseq@keys@unknown@handlecolor{% - \sseq@add@tikzkey@to@options{\@nx\tikz@addoption{\@nx\tikz@compat@color@set{\tikz@key}}}% - \sseq@add@tikzkey@to@options{\def\@nx\tikz@textcolor{\tikz@key}}% + \sseq@add@tikzkey@to@options{\@nx\sseq@options@secondpass{\@nx\tikz@addoption{\@nx\tikz@compat@color@set{\tikz@key}}}}% + \sseq@add@tikzkey@to@options{\@nx\sseq@options@secondpass{\def\@nx\tikz@textcolor{\tikz@key}}}% } %%% \sseq@keys@try@addtooptions @@ -223,9 +232,10 @@ \def\pgfkeysdefaultpath{#1/}% \def\next{\egroup\@ifnextchar\sseq@nil{\@xp\@secondoftwo\@gobble}{\sseq@keys@try@addtooptions@}}% \pgfkeysifdefined{#1/\pgfkeyscurrentname/.@cmd}{% + \edef\pgfkeyscurrentkey{#1/\pgfkeyscurrentname}% \ifx\pgfkeyscurrentvalue\pgfkeysnovalue@text% Hmm... no value \pgfkeysifdefined{#1/\pgfkeyscurrentname/.@def}% - {\pgfkeysgetvalue{#1/\pgfkeyscurrentname/.@def}{\pgfkeyscurrentvalue}} + {\pgfkeysgetvalue{#1/\pgfkeyscurrentname/.@def}{\pgfkeyscurrentvalue}}% {}% no default, so leave it \fi% \pgfkeysgetvalue{#1/\pgfkeyscurrentname/.@cmd}{\pgfkeys@code}% @@ -236,29 +246,70 @@ }{% \pgfkeysifdefined{#1/\pgfkeyscurrentname}{% \egroup - \sseq@add@tikzkey@to@options{\@nx\pgfkeyssetvalue{#1/\pgfkeyscurrentname}{\unexpanded\@xp{\pgfkeyscurrentvalue}}}% + \sseq@add@tikzkey@to@options{\@nx\sseq@options@secondpass{\@nx\pgfkeyssetvalue{#1/\pgfkeyscurrentname}{\unexpanded\@xp{\pgfkeyscurrentvalue}}}}% \def\next{\@xp\@firstoftwo\sseq@gobble@to@nil}% }{}% }% \next } +% Iterate over list and run \pgfkeysalso's when we find them. Note that we use our variants of \pgfkeys@case@... which hand control back to this command, +% so this is recursive -- the result is guaranteed not to have any instance of \pgfkeysalso in it! \def\sseq@keys@addtooptions@checkalso#1{% \let\pgfkeys@case@one\sseq@pgfkeys@case@one@store \let\pgfkeys@case@two@extern\sseq@pgfkeys@case@two@extern@store \sseq@keys@addtooptions@checkalso@#1\pgfkeysalso\sseq@nil } + \def\sseq@keys@addtooptions@checkalso@#1\pgfkeysalso#2{% - \sseq@add@tikzkey@to@options{\unexpanded{#1}}% - \ifx\sseq@nil#2% + \def\sseq@tempa{/tikz/}% + \def\sseq@tempb{/pgf/}% + % This is an extra hook I needed to add so that my own keys can execute code when they need to... + \sseq@keys@addtooptions@checkdo#1\sseq@keys@do\sseq@nil + \ifx\sseq@nil#2% We're done, restore pgfkeys. \let\pgfkeys@case@one\sseq@pgfkeys@case@one@save \let\pgfkeys@case@two@extern\sseq@pgfkeys@case@two@extern@save \else - \pgfkeysalso{#2}% - \@xp\sseq@keys@addtooptions@checkalso@ + \ifx\expandafter#2 % if they wanted to expand the first token, handle that + \sseq@add@tikzkey@to@options{\sseq@options@secondpass@iftikz{\relax\relax}}% The last token was an \expandafter, we need to keep it from doing anything + \@xptwo\sseq@keys@addtooptions@checkalso@xp + \else + \pgfkeysalso{#2}% + \@xptwo\sseq@keys@addtooptions@checkalso@ + \fi + \fi +} + +\def\sseq@keys@addtooptions@checkalso@xp#1{% + \@xp\pgfkeysalso\@xp{#1}% + \sseq@keys@addtooptions@checkalso@ +} + +% Used to get collections code to run right. +\def\sseq@keys@addtooptions@checkdo#1\sseq@keys@do#2{% + \sseq@add@tikzkey@to@options{\sseq@options@secondpass@iftikz{\unexpanded{#1}}}% + \ifx#2\sseq@nil\else + #2% + \@xp\sseq@keys@addtooptions@checkdo + \fi +} + +% This has to be expandable, so \sseq@tempa and \sseq@tempb are set to "/tikz/" and "/pgf/" ahead of time +% Defer the command if it is in directories /pgf or /tikz, otherwise run it now. TODO: explain here why we need this. +\def\sseq@options@secondpass@iftikz{% + \ifx\pgfkeysdefaultpath\sseq@tempa + \@nx\sseq@options@secondpass + \else + \ifx\pgfkeysdefaultpath\sseq@tempb + \@nx\sseq@options@secondpass + \else + \@xptwo\@firstofone + \fi \fi } + +% Here we hook into pgfkeys. This is remarkably easy! \let\sseq@pgfkeys@case@one@save\pgfkeys@case@one \let\sseq@pgfkeys@case@two@extern@save\pgfkeys@case@two@extern \def\sseq@pgfkeys@case@one@store{% @@ -275,7 +326,7 @@ \else% % The following line is the only change, it used to be (roughly) \pgfkeyssetvalue{\pgfkeyscurrentkey}{\pgfkeyscurrentvalue} % which would immediately set the value. Instead we store in it \sseq@savedoptioncode - \sseq@add@tikzkey@to@options{\@nx\pgfkeyssetvalue{\pgfkeyscurrentkey}{\unexpanded\@xp{\pgfkeyscurrentvalue}}}% + \sseq@add@tikzkey@to@options{\@nx\sseq@options@secondpass{\@nx\pgfkeyssetvalue{\pgfkeyscurrentkey}{\unexpanded\@xp{\pgfkeyscurrentvalue}}}}% \fi% } @@ -296,6 +347,7 @@ /sseqpages/class/.is family, /sseqpages/class/label/.is family, /sseqpages/class/label/.unknown/.code={\sseq@keys@unknown}, + /sseqpages/class/label/pin/.unknown/.code={\sseq@keys@unknown}, /sseqpages/class/node texts/.is family, /sseqpages/class/node texts/.unknown/.code={\sseq@passoptionto{/tikz}}, /sseqpages/differential/.is family, @@ -307,6 +359,7 @@ /sseqpages/tikz primitives/.is family, /sseqpages/tikz primitives/.unknown/.code={\sseq@keys@unknown}, % One off directories + /sseqpages/fit/.is family, /sseqpages/fit/.unknown/.code={\sseq@passoptionto{/sseqpages}}, /sseqpages/foreach/.unknown/.code={\sseq@passoptionto{/pgf/foreach}}, /sseqpages/class placement/.unknown/.code={\sseq@passoptionto{/tikz}} @@ -314,10 +367,18 @@ \pgfqkeys{/sseqpages/class}{shape/.code={\edef\tikz@shape{\pgfkeyscurrentname}}} % shape=whatever shape passing +\newif\ifsseq@pin \pgfqkeys{/sseqpages/class/label}{% maybe implement multipart node labels this way? No way! node/.sseq @ first pass code={\sseq@classlabelfalse}, - inside/.sseq @ first pass code={\sseq@classlabelfalse} + inside/.sseq @ first pass code={\sseq@classlabelfalse}, + pin/.sseq @ first pass code = { + \let\sseq@savedoptioncode@save\sseq@savedoptioncode + \sseq@processoptions{class/label/pin}{#1} + \edef\sseq@savedoptioncode{\unexpanded\@xp{\sseq@savedoptioncode@save}\@nx\sseq@d@addto@macro\@nx\sseq@pinoptions{\unexpanded\@xp{\sseq@savedoptioncode}}} + }, + pin/.sseq @ second pass append code = {\sseq@pintrue} } +\def\sseq@pinoptions{} %% label directions \def\sseq@labeldirectionlist{\\{above}\\{below}\\{left}\\{right}\\{above left}\\{above right}\\{below left}\\{below right}} @@ -342,8 +403,7 @@ -\sseq@setlabeldirectionkeys{/sseqpages/class/label}[/.sseq @ first pass code] - {\sseq@classlabeltrue\def\sseq@class@labelposition@name{#1}\def\sseq@class@labelposition@distance{##1}} +\sseq@setlabeldirectionkeys{/sseqpages/class/label}[/.sseq @ first pass code]{\sseq@classlabeltrue} \sseq@setlabeldirectionkeys{/sseqpages/class/label}[/.sseq @ second pass append code]{\sseq@class@positionlabel{#1}{##1}} \sseq@setlabeldirectionkeys{/sseqpages/class/label}[/.default]{\sseq@defaultlabeldistance{#1}} \sseq@setlabeldirectionkeys{/sseqpages/global/class/label}[/.default]{\sseq@defaultlabeldistance{#1}} @@ -355,12 +415,12 @@ label distance/.code={\sseq@setdefaultlabeldistances{#1}} } -\def\sseq@class@positionlabel#1#2{\sseq@pgfkeysdocommand{#1}{#2}} +\def\sseq@class@positionlabel#1#2{\ifx\tikz@fig@name\undefined\else\sseq@pgfkeysdocommand{#1}{#2 of \tikz@fig@name}\fi} \sseq@addtostorelist\sseq@classlabeltextfn{} % \sseq@classlabeltextfn is public via "class label handler" -\let\sseq@classlabeltextfn@default\@gobble +\def\sseq@classlabeltextfn@default#1{\def\processedlabel{#1}} \def\sseq@labeltextfn#1{#1} % labeltextfn is private \def\sseq@labeltextfn@rotatescale#1{% \@nx\ifmmode @@ -403,8 +463,15 @@ \def\sseq@edgeoptionhook{}% This is just to make description work. +%% Labels +%% The code for this that actually does most of the work is inside of sseqmain.code.tex -- search for "Labels" +%% This just handles the interface with the keyvalue system here. + + %% Quote handling % \sseq@handlequote will be installed later as the 'first char syntax' for ". +% Problem is that 'first char syntax' isn't allowed to care what directory it is in, but we need different handling +% for classes versus edges versus scopes. Solution is to use \pgfkeysalso and then define the handler in a key. \def\sseq@protectlabel{\@nx\sseq@protectlabel\@nx} \def\sseq@handlequote#1{\pgfkeysalso{handle quote=#1}} \pgfkeys{% @@ -415,20 +482,13 @@ \let\tikz@quotes@as\tikz@quotes@as@save }, /sseqpages/handle quote/.code={% - \begingroup % group gets ended by handleedgequotes \let\tikz@quotes@as\sseq@handleedgequotes \tikz@quote@parser{#1}% + \let\tikz@quotes@as\tikz@quotes@as@save } } -\def\sseq@processlabels@default{% - \global\let\sseq@classnodetext\pgfutil@empty - \global\let\sseq@classnodetextoptions\pgfutil@empty - \global\let\sseq@classlabelnodes\pgfutil@empty -} -\let\sseq@processlabels\sseq@processlabels@default - \def\sseq@handlescopequotes#1#2{% We use this via \let\tikz@quotes@as\sseq@handleclassquotes /utils/exec={% so it's called inside \pgfkeysalso{stuff}. Need to surround with /utils/exec={} to get out. \global\let\sseq@classnodetext\pgfutil@empty% @@ -442,103 +502,6 @@ % so it's called inside \pgfkeysalso{stuff}. Need to surround with /utils/exec={} to get out. \def\sseq@handleclassquotes#1#2{/utils/exec={\sseq@d@addto@macro\sseq@processlabels{\sseq@handleclassquotes@inner{#1}{#2}}}} -\def\sseq@handleclassquotes@inner#1#2{% - \begingroup\pgfscope - \sseq@options@firstpassmode - \sseq@thesseqstyle - \sseq@thelabelstyle - \sseq@theclasslabelstyle - \the\sseq@scope@toks - \sseq@options@normalmode - \sseq@processoptions{class/label}{#2}% - \ifx\sseq@classlabeltextfn\@gobble - \def\processedlabel{#1}% - \else - \sseq@classlabeltextfn{#1}% labeltextfn is a private handler, classlabeltextfn is exposed via "class label handler" - \fi - \ifsseq@classlabel - \sseq@options@firstpassmode - \the\sseq@outerclasslabelstyle - \sseq@xprotected@addto@macro\sseq@classlabelnodes{ - \@nx\ifsseq@needstikz - node[ - /sseqpages/class/label, - /utils/exec={ - \let\@nx\sseq@tikz@transform@save\@nx\tikz@transform - \let\@nx\tikz@transform\relax % The next line was set up to fix the classlabelstyle glitch - \the\sseq@sseqstyle\@nx\the\sseq@sseqstyle@page - \the\sseq@labelstyle\@nx\the\sseq@labelstyle@page\the\sseq@classlabelstyle\@nx\the\sseq@classlabelstyle@page - \sseq@theouterclasslabelstyle\unexpanded\@xp{\sseq@savedoptioncode}% - % \@nx\iftikz@fullytransformed\@nx - % \@nx\tikz@fullytransformedtrue - % \else - % \@nx{\@nx\pgftransformresetnontranslations\@nx\sseq@globalrotatetransform} - % \@nx\fi - \let\@nx\tikz@transform\@nx\sseq@tikz@transform@save - }% - ]{\sseq@labeltextfn{\processedlabel}}% - \@nx\else - \@nx\node[ - /sseqpages/class/label, - /utils/exec={ - \let\@nx\sseq@tikz@transform@save\@nx\tikz@transform - \let\@nx\tikz@transform\relax % The next line was set up to fix the classlabelstyle glitch - \the\sseq@sseqstyle\@nx\the\sseq@sseqstyle@page - \the\sseq@labelstyle\@nx\the\sseq@labelstyle@page\the\sseq@classlabelstyle\@nx\the\sseq@classlabelstyle@page - \sseq@theouterclasslabelstyle\unexpanded\@xp{\sseq@savedoptioncode} - % \@nx\iftikz@fullytransformed\@nx - % \@nx\tikz@fullytransformedtrue - % \else - % \@nx{\@nx\pgftransformresetnontranslations\@nx\sseq@globalrotatetransform} - % \@nx\fi - \let\@nx\tikz@transform\@nx\sseq@tikz@transform@save - } - ]{\unexpanded\@xp{\@xp\sseq@labeltextfn\@xp{\processedlabel}}};% - \@nx\fi - }% - \else - \sseq@options@firstpassmode - \the\sseq@innerclasslabelstyle - \sseq@options@normalmode - \sseq@protectedeval{\@nx\pgfqkeys{/sseqpages/class/label}{#2}}% - \sseq@protected@xdef\sseq@classnodetext{\processedlabel}% - \xdef\sseq@classnodetextoptions{% - %\unexpanded{\def\pgfkeysdefaultpath{/sseqpages/class/node texts/}}% - \sseq@thelabelstyle\sseq@theinnerclasslabelstyle\unexpanded\@xp{\sseq@savedoptioncode}% - }% - \fi - \endpgfscope\endgroup -} - -\def\sseq@handleedgequotes#1#2{% We use this via \let\tikz@quotes@as\sseq@handleedgequotes - /utils/exec={% so it's called inside \pgfkeysalso{stuff}. Need to surround with /utils/exec={} to get out. - \endgroup - \let\sseq@savedoptioncode@save\sseq@savedoptioncode - \sseq@processoptions{label}{#2} - \sseq@needstikztrue - \let\sseq@temp\sseq@savedoptioncode - \let\sseq@savedoptioncode\sseq@savedoptioncode@save - \sseq@e@addto@options{ - \@nx\tikzset{ - every to/.append style={ - edge node={ - node [/sseqpages/label, - /utils/exec={ - \let\@nx\sseq@tikz@transform@save\@nx\tikz@transform - \let\@nx\tikz@transform\relax - \@nx\sseq@thelabelstyle\@nx\sseq@theedgelabelstyle - \unexpanded\@xp{\sseq@temp} - \ifsseq@rotatelabels\iftikz@fullytransformed\else\@nx\tikz@fullytransformedtrue\@nx\tikz@addtransform{\@nx\pgftransformresetnontranslations\@nx\sseq@globalrotatetransform}\fi\fi - \unexpanded\@xp{\sseq@edgeoptionhook} % this is just to make description work - \let\@nx\tikz@transform\@nx\sseq@tikz@transform@save - } - ]{\sseq@labeltextfn{#1}} - } - } - } - } - } -} \def\sseq@checktransform@error{\sseq@error@nn{illegal-transform}} @@ -550,6 +513,7 @@ \let\sseq@tikzprimitives@coords@maybeclass\sseq@tikzprimitives@coords@notaclass \let\sseq@checktransform\@gobbletwo \let\sseq@tikz@shifttransform\sseq@okayshifttransform + % TODO: This needs fixing: %(((((((((((((((((( \def\class##1){\sseq@setthiscall{\string\class##1)}\sseq@error@x{standard-parse}{\string\class}}% \def\replaceclass##1){\sseq@setthiscall{\string\replaceclass##1)}\sseq@error@x{standard-parse}{\string\replaceclass}}% @@ -560,6 +524,7 @@ \def\structlineoptions##1)##2){\sseq@setthiscall{\string\structlineoptions##1)##2)}\sseq@error@x{standard-parse}{\string\structlineoptions}}% } +% I don't think this is ever actually used... \def\sseq@nodeparse{% \let\sseq@tikzprimitives@coords@maybeclass\sseq@tikzprimitives@coords@maybeclass@save \let\sseq@tikzprimitives@coords@maybeclass @@ -596,10 +561,12 @@ background/.sseq @ first pass code={\sseq@error@n{option-tikz-prims-only}{background}} } +% Some class options. All of these will make changes local to the current \class command. They are communicated to \class via these commands, +% which we initialize here as empty. \def\sseq@class@tag{} \def\sseq@class@tagprefix{} \def\sseq@class@name{} -\def\sseq@namehandler{}%\@xp\sseq@normalizepolynomial\@xp{\sseq@class@name}\let\sseq@class@name\sseq@polynomial} +\def\sseq@namehandler{} \def\sseq@currenttag{\sseq@class@tag}% for the user ?? \def\sseq@tooltip{} \pgfqkeys{/sseqpages/scope}{ @@ -607,14 +574,16 @@ tag prefix/.code={\pgfkeys@spdef\temp{#1}\sseq@e@addto@macro\sseq@class@tagprefix{\unexpanded\@xp{#1}}} } +\def\sseq@classinsert{} \pgfqkeys{/sseqpages/class}{ name/.code={\def\sseq@class@name{#1}\pgfkeysalso{/sseqpages/alias=#1}}, - show name/.code={\def\sseq@class@showname{#1}}, + show name/.store in=\sseq@class@showname, page/.code={\sseq@getnumrange\sseq@class@page{#1}},% page & gen are only for \classoptions. generation/.code={\sseq@getnumrange\sseq@gen{#1}}, % \class tests if \sseq@class@page is set and throw an error if so. tag/.code={\sseq@d@addto@macro\sseq@class@tag{#1}}, - offset/.code={\def\sseq@tempoffset{#1}}, - tooltip/.sseq @ first pass code={\def\sseq@tooltip{#1}} + offset/.store in=\sseq@tempoffset, + tooltip/.sseq @ first pass code={\def\sseq@tooltip{#1}}, + insert/.store in=\sseq@classinsert } \pgfqkeys{/sseqpages/struct line}{ @@ -647,8 +616,9 @@ } \pgfqkeys{/sseqpages}{needs tikz/.code=\sseq@needstikztrue} +% All of these things need tikz to draw but otherwise require no special handling. \sseq@needstikzandpass{/sseqpages}{% - shade, blend mode, pattern, path picture, path fading, decorate, pin, label + shade, blend mode, pattern, path picture, path fading, decorate, pin, label % should pin be here? } \sseq@needstikzandpass{/sseqpages/differential}{% @@ -671,8 +641,8 @@ % rectangle split/.code=\sseq@needstikzandpass, % align/.code=\sseq@needstikzandpass, -\sseq@addtostorelist\sseq@runoffarrow@start@differential@spec{...} -\sseq@addtostorelist\sseq@runoffarrow@end@differential@spec{...} +\sseq@addtostorelist\sseq@runoffarrow@start@differential@spec{} +\sseq@addtostorelist\sseq@runoffarrow@end@differential@spec{>} \sseq@addtostorelist\sseq@runoffarrow@start@structline@spec{...} \sseq@addtostorelist\sseq@runoffarrow@end@structline@spec{...} \sseq@pgfqkeysdirlist{/sseqpages/global,/sseqpages}{ @@ -704,11 +674,24 @@ %% Add key code to \sseq@savedoptioncode % #1 -- a list of directories to search % #2 -- keys +% +% This is pretty similar in basic concept to \sseq@processoptions, but instead of using the .unknown handlers to walk up the directory, +% it just tries the key in each directory in the list. I'm not actually sure anymore why it was important to do it this way, but there probably was a good reason... +% % This is a faster and sloppier way of doing: -%\def\sseq@temp{#1} -%\pgfqkeys{/sseqpages/alwaysunknown}{#2} +% \def\sseq@temp{#1} +% \pgfqkeys{/sseqpages/alwaysunknown}{#2} % and defining an event handler: alwaysunknown/.unknown/.code={\@xp\sseq@keys@try@addtooptions\@xp{\sseq@temp}{}{\sseq@keys@unknown} +% That basically takes advantage of the pgfkeys parser but gives me back control over what to do with the parsed things. +% +% For some reason I made the probably misguided decision that that approach was too slow, even though this isn't performance +% critical code. Maybe I had a better reason for doing this that I can't remember. Instead I copied pgfkeys but deleted all the +% parts that are useless in this context, which is most of it. Occasionally bugs crop up here when it turns out I deleted a little too much. +% +% This uses a hook \sseq@addstylecodetooptions@unknown to allow the sseqs style to sift out the nonglobal keys and handle them differently. +% % Copied with modification from /pgf/utilities/pfgkeys.code.tex + \def\sseq@addstylecodetooptions#1#2{% \def\sseq@directorylist{#1}% \sseq@simple@pgfkeys@parse#2,\pgfkeys@mainstop @@ -733,6 +716,7 @@ \pgfkeys@spdef\pgfkeyscurrentvalue{#2}% \ifx\pgfkeyscurrentkey\pgfkeys@empty\else \def\next{\@xp\sseq@keys@try@addtooptions\@xp{\sseq@directorylist}{}{\sseq@addstylecodetooptions@unknown}}% + % We deleted the general "first char syntax" handler, so we need to do our own check for the quote. \sseq@simple@pgfkeys@checkquote#1\sseq@nil{% \def\pgfkeyscurrentname{handle quote}% \def\pgfkeyscurrentvalue{#1}% @@ -747,6 +731,7 @@ \@xp\next \fi } +% This is a hook for the "sseqs" style. \let\sseq@addstylecodetooptions@unknown\sseq@keys@unknown \long\def\sseq@simple@pgfkeys@checkquote#1#2\sseq@nil{% @@ -757,17 +742,42 @@ \fi } -\def\sseq@sseqstyle@globalpart{} - \def\sseq@stylelist{} \def\sseq@clearchangestyles{} +% The basic idea here is we make a tokens list \sseq@structlinestyle and define a key "struct lines" that takes a list of keys +% and adds the keys to \sseq@structlinestyle. In order to do this, I need some special trick to delete spaces. +% The macro \sseq@setmacronospaces defined in spectralsequences.sty accomplishes this. \def\sseq@newstyles#1#2{\def\sseq@temppath{#1}\sseq@newstyles@#2,\sseq@nil} \def\sseq@newstyles@#1,{\sseq@newsseqstyle{\sseq@trimleadingspaces#1}\@ifnextchar\sseq@nil{\@gobble}{\sseq@newstyles@}} -\def\sseq@set@newstyle#1{\pgfqkeys{/sseqpages}{#1}\pgfqkeys{/sseqpages/global}{#1}\pgfqkeys{/sseqpages/global/default}{#1}\pgfqkeys{/sseqpages/first pass}{#1}} +\def\sseq@set@newstyle#1{\pgfqkeys{/sseqpages}{#1}\pgfqkeys{/sseqpages/global}{#1}\pgfqkeys{/sseqpages/global/default}{#1}} + +% Here are two useful wrappers around addstylecodetotoks. + +% #1 -- token list +% #2 -- path +% #3 -- code +\def\sseq@addstylecodetotoks#1#2#3{% + \let\sseq@savedoptioncode@store\sseq@savedoptioncode + \edef\sseq@savedoptioncode{\the#1}% + \sseq@addstylecodetooptions{#2}{#3}% + #1\@xp{\sseq@savedoptioncode}% + \let\sseq@savedoptioncode\sseq@savedoptioncode@store +} + +% #1 -- macro +% #2 -- path +% #3 -- code +\def\sseq@addstylecodetomacro#1#2#3{% + \let\sseq@savedoptioncode@store\sseq@savedoptioncode + \let\sseq@savedoptioncode#1% + \sseq@addstylecodetooptions{#2}{#3}% + \let#1\sseq@savedoptioncode + \let\sseq@savedoptioncode\sseq@savedoptioncode@store +} \def\sseq@newsseqstyle#1{% \sseq@setmacronospaces\sseq@tempcmd{sseq@#1style}% @@ -780,23 +790,15 @@ \sseq@x@addto@macro\sseq@clearchangestyles{\sseq@tempcmdb{}}% \sseq@set@newstyle{% #1s/.ecode={% - \let\@nx\sseq@savedoptioncode@store\@nx\sseq@savedoptioncode - \edef\@nx\sseq@savedoptioncode{\@nx\the\sseq@tempcmd}% - \@nx\sseq@addstylecodetooptions{\sseq@temppath}{##1}% - \sseq@tempcmd\@nx\@xp{\@nx\sseq@savedoptioncode}% + \@nx\sseq@addstylecodetotoks{\sseq@tempcmd}{\sseq@temppath}{##1} \@nx\ifsseq@inprogress \@nx\sseq@savedpaths@xadd{\sseq@tempcmd{\@nx\the\sseq@tempcmd}}% \@nx\fi - \let\@nx\sseq@savedoptioncode\@nx\sseq@savedoptioncode@store },% change #1s/.ecode={% \@nx\ifsseq@ispageenv\@nx\else\@nx\sseq@error@nn{change-style-data}{#1}{##1}\@nx\fi \@nx\ifsseq@hasname\@nx\else\@nx\sseq@error@nn{change-style-standalone}{#1}{##1}\@nx\fi - \let\@nx\sseq@savedoptioncode@store\@nx\sseq@savedoptioncode - \edef\@nx\sseq@savedoptioncode{\@nx\the\sseq@tempcmdb}% - \@nx\sseq@addstylecodetooptions{\sseq@temppath}{##1}% - \sseq@tempcmdb\@nx\@xp{\@nx\sseq@savedoptioncode}% - \let\@nx\sseq@savedoptioncode\@nx\sseq@savedoptioncode@store + \@nx\sseq@addstylecodetotoks{\sseq@tempcmdb}{\sseq@temppath}{##1} } }% } @@ -808,12 +810,13 @@ % sseqs has to be handled separately, because it must decide whether an option is a global option or not % and handle them at different times. This makes the code a little trickier. +\def\sseq@sseqstyle@globalpart{} \sseq@g@addto@macro\sseq@stylelist{\sseq@sseqstyle{\the\sseq@sseqstyle}}% \sseq@g@addto@macro\sseq@clearchangestyles{\sseq@sseqstyle@page{}}% \sseq@set@newstyle{ sseqs/.code={% - \let\sseq@savedoptioncode@store\sseq@savedoptioncode - \let\sseq@savedoptioncode\sseq@sseqstyle@globalpart + % This will get called on each key that isn't a defined global option. Then we add it to \sseq@sseqstyle to be applied + % locally to absolutely everything. \def\sseq@addstylecodetooptions@unknown{% \let\sseq@sseqstyle@globalpart\sseq@savedoptioncode \edef\sseq@savedoptioncode{\the\sseq@sseqstyle}% @@ -821,32 +824,30 @@ \sseq@sseqstyle\@xp{\sseq@savedoptioncode}% \let\sseq@savedoptioncode\sseq@sseqstyle@globalpart }% - \sseq@addstylecodetooptions{/sseqpages/global}{#1}% - \let\sseq@sseqstyle@globalpart\sseq@savedoptioncode + \sseq@addstylecodetomacro\sseq@sseqstyle@globalpart{/sseqpages/global}{#1}% \ifsseq@inprogress \sseq@savedpaths@xadd{\sseq@sseqstyle{\the\sseq@sseqstyle}}% \fi + % Restore hook \let\sseq@addstylecodetooptions@unknown\sseq@keys@unknown - \let\sseq@savedoptioncode\sseq@savedoptioncode@store },% + % It's not clear to me that "change sseqs" should even exist as an option. change sseqs/.code={% \ifsseq@ispageenv\else\sseq@error@nn{change-style-data}{sseq}{#1}\fi \ifsseq@hasname\else\sseq@error@nn{change-style-standalone}{sseq}{#1}\fi - \let\sseq@savedoptioncode@store\sseq@savedoptioncode - \edef\sseq@savedoptioncode{\the\sseq@sseqstyle@page}% - \sseq@addstylecodetooptions{\sseq@temppath}{#1}% - \sseq@sseqstyle@page\@xp{\sseq@savedoptioncode}% - \let\sseq@savedoptioncode\sseq@savedoptioncode@store + \sseq@addstylecodetotoks{\sseq@sseqstyle@page}{\sseq@temppath}{#1}% } } +% sseq needs special handling, so is done by hand above. %\sseq@newstyles{/sseqpages/}{sseq}% DON'T make this /global/default! Bad things will happen. \sseq@newstyles{/sseqpages/label,/sseqpages}{edge, label, edge label, differential label, struct line label} \sseq@newstyles{/sseqpages/class,/sseqpages}{class, permanent cycle, transient cycle, this page cycle} \sseq@newstyles{/sseqpages/differential,/sseqpages}{differential} \sseq@newstyles{/sseqpages/struct line,/sseqpages}{struct line, this page struct line} \sseq@newstyles{/sseqpages/class/label}{class label, inner class label, outer class label} +\sseq@newstyles{/sseqpages/class/label/pin}{pin} \sseq@newstyles{/sseqpages/tikz primitives}{tikz primitive} \sseq@newstyles{/sseqpages/fit}{circle class} @@ -860,11 +861,6 @@ permanent classes/.code={\pgfkeysalso{permanent cycles={#1}}}, transient classes/.code={\pgfkeysalso{transient cycles={#1}}}, this page classes/.code={\pgfkeysalso{this page cycles={#1}}}, - cycle style/.code={\pgfkeysalso{class style={#1}}}, - permanent class style/.code={\pgfkeysalso{permanent cycle style={#1}}}, - transient class style/.code={\pgfkeysalso{transient cycle style={#1}}}, - this page class style/.code={\pgfkeysalso{this page cycle style={#1}}}, - class label position/.code={\pgfkeysalso{class label positions={#1}}} }% \def\sseq@newplotstyle#1{ @@ -874,21 +870,13 @@ \@xp\def\sseq@tempcmdb{} \pgfqkeys{/sseqpages/global}{% #1 style/.ecode={ - \unexpanded{\let\sseq@savedoptioncode@store\sseq@savedoptioncode} - \let\@nx\sseq@savedoptioncode\@xp\@nx\sseq@tempcmd - \unexpanded{\sseq@addstylecodetooptions{/tikz}}{##1} - \let\@xp\@nx\sseq@tempcmd\@nx\sseq@savedoptioncode - \unexpanded{\let\sseq@savedoptioncode\sseq@savedoptioncode@store} + \@nx\sseq@addstylecodetomacro{\@xp\@nx\sseq@tempcmd}{/tikz}{##1} } } % Only difference here is \sseq@tempcmdb -- which puts it in the default code -- instead of \sseq@tempcmd \pgfqkeys{/sseqpages/global/default}{% #1 style/.ecode={ - \unexpanded{\let\sseq@savedoptioncode@store\sseq@savedoptioncode} - \let\@nx\sseq@savedoptioncode\@xp\@nx\sseq@tempcmdb - \unexpanded{\sseq@addstylecodetooptions{/tikz}}{##1} - \let\@xp\@nx\sseq@tempcmdb\@nx\sseq@savedoptioncode - \unexpanded{\let\sseq@savedoptioncode\sseq@savedoptioncode@store} + \@nx\sseq@addstylecodetomacro{\@xp\@nx\sseq@tempcmdb}{/tikz}{##1} } } } @@ -896,10 +884,152 @@ \def\sseq@newplotstyles#1{\def\sseq@temppath{#1}\sseq@newplotstyles@#1,\sseq@nil} \def\sseq@newplotstyles@#1,{\sseq@newplotstyle{\sseq@trimleadingspaces#1}\@ifnextchar\sseq@nil{\@gobble}{\sseq@newplotstyles@}} - \sseq@newplotstyles{x tick, y tick} +%% +%% +%% Families (also called collections in code) +%% +%% These are supposed to make it easy to display / hide and change appearance of logically connected families of classes. +%% In order to allow a set of options to be given that applies uniformly to all features, we separately apply the options in each of these bins. +%% + + +\def\sseq@featurelist{\\{class}\\{differential}\\{structline}\\{circleclass}\\{tikzprimitive}} +\def\sseq@mapfeaturelist#1{\def\\##1{#1}\sseq@featurelist} + +\def\sseq@familylist{} + +\def\sseq@collections@featuretype{} +\def\sseqnewfamily#1{% + % Make five bins associated to the new family, one for each feature type. Add them to storelist with empty defaults. + \sseq@mapfeaturelist{ + \@xp\sseq@setmacronospaces\csname sseq@tempcmd@##1\endcsname{sseq@user@#1@##1@style} + \@xp\sseq@setmacronospaces\csname sseq@tempcmd@##1@default\endcsname{sseq@user@#1@##1@style@default} + \sseq@eval{\@nx\sseq@addtostorelist\@xptwo\@nx\csname sseq@tempcmd@##1\endcsname{\@xptwo\@nx\csname sseq@tempcmd@##1@default\endcsname}} + \@xptwo\def\csname sseq@user@#1@##1@style@default\endcsname{} + } + % This is for deciding what set of options to apply to a feature + \@xp\sseq@setnospaces\csname sseq@tempcmd\endcsname{sseq@user@#1} +% + % A flag to decide whether to draw the family. Set/unset using "draw family" and "no family". + \@xp\sseq@addtostorelist\csname sseq@#1@maybedraw\endcsname{} + \pgfqkeys{/sseqpages/global}{% + #1 style/.ecode={% + \@nx\sseq@addstylecodetomacro\@xp\@nx\sseq@tempcmd@class{/sseqpages/class,/sseqpages/collections/class}{##1}% + \@nx\sseq@addstylecodetomacro\@xp\@nx\sseq@tempcmd@differential{/sseqpages/differential,/sseqpages/collections/differential}{##1}% + \@nx\sseq@addstylecodetomacro\@xp\@nx\sseq@tempcmd@structline{/sseqpages/struct line,/sseqpages/collections/struct line}{##1}% + \@nx\sseq@addstylecodetomacro\@xp\@nx\sseq@tempcmd@circleclass{/sseqpages/fit,/sseqpages/collections/fit}{##1}% + \@nx\sseq@addstylecodetomacro\@xp\@nx\sseq@tempcmd@tikzprimitive{/sseqpages/tikz primitives,/sseqpages/collections/tikz primitives}{##1}% + }, + draw #1/.ecode = {\def\@xp\@nx\csname sseq@#1@maybedraw\endcsname{\@nx\sseq@drawtrue}}, + no #1/.ecode = {\def\@xp\@nx\csname sseq@#1@maybedraw\endcsname{\@nx\sseq@drawfalse}} + }% + \pgfqkeys{/sseqpages/global/default}{% + #1 style/.ecode={% + \@nx\sseq@addstylecodetomacro\@xp\@nx\sseq@tempcmd@class@default{/sseqpages/class}{##1}% + \@nx\sseq@addstylecodetomacro\@xp\@nx\sseq@tempcmd@differential@default{/sseqpages/differential}{##1}% + \@nx\sseq@addstylecodetomacro\@xp\@nx\sseq@tempcmd@structline@default{/sseqpages/struct line}{##1}% + \@nx\sseq@addstylecodetomacro\@xp\@nx\sseq@tempcmd@circleclass@default{/sseqpages/fit}{##1}% + \@nx\sseq@addstylecodetomacro\@xp\@nx\sseq@tempcmd@tikzprimitive@default{/sseqpages/tikz primitives}{##1}% + }, + draw #1/.ecode = {\def\@xp\@nx\csname sseq@#1@maybedraw@default\endcsname{\@nx\sseq@drawtrue}}, + no #1/.ecode = {\def\@xp\@nx\csname sseq@#1@maybedraw@default\endcsname{\@nx\sseq@drawfalse}} + }% +% + \pgfqkeys{/sseqpages}{ + #1/.ecode={ + \@nx\sseq@d@addto@macro\@nx\sseq@familylist{\@nx\csname sseq@#1@maybedraw\endcsname} + \@nx\sseq@options@secondpass{ + \unexpanded\@xp{\@xp\csname\sseq@tempcmd @\sseq@collections@featuretype @style\endcsname} + } + } + } +} + + + + +\def\sseq@collections@classlabels@hook{} +\def\sseq@collections@innerclasslabels@hook{} +\def\sseq@collections@outerclasslabels@hook{} +\def\sseq@collections@pins@hook{} + +\def\sseq@collections@labels@hook{} +\def\sseq@collections@edgelabels@hook{} +\def\sseq@collections@differentiallabels@hook{} +\def\sseq@collections@structlinelabels@hook{} + +\def\sseq@collections@setempty#1{\sseq@collections@setempty@#1,\sseq@nil} +\def\sseq@collections@setempty@#1,{ + \pgfqkeys{/sseqpages/collections}{ + class/#1/.code={}, + differential/#1/.code={}, + struct line/#1/.code={}, + fit/#1/.code={}, + tikz primitives/#1/.code={} + } + \@ifnextchar\sseq@nil{\@gobble}{\sseq@collections@setempty@} +} + +\sseq@collections@setempty{% + classes, cycles, permanent classes, permanent cycles, transient classes, transient cycles, this page classes, this page cycles, + edges, differentials,struct lines, this page struct lines,circleclasses, tikz primitives, + labels, edge labels, differential labels, struct line labels, + class labels, inner class labels, outer class labels,pins +} + +% #1 -- path +% #2 -- hook name +% #3 -- code +\def\sseq@collections@addtohook#1#2#3{ + \sseq@keys@do{ + \let\sseq@savedoptioncode@store\sseq@savedoptioncode\let\sseq@savedoptioncode\empty + \pgfqkeys{#1}{#3} + \edef\sseq@savedoptioncode{\unexpanded\@xp{\sseq@savedoptioncode@store}\def\@nx#2{\unexpanded\@xp{\sseq@savedoptioncode}}} + } +} + +\pgfqkeys{/sseqpages/collections}{ + class/classes/.style={/sseqpages/class/.cd,#1}, + class/cycles/.style={/sseqpages/class/.cd,#1}, + class/permanent classes/.code={\ifsseq@permanentcycle\pgfkeysalso{/sseqpages/class/.cd,#1}\fi}, + class/permanent cycles/.code={\ifsseq@permanentcycle\pgfkeysalso{/sseqpages/class/.cd,#1}\fi}, + class/transient classes/.code={\ifsseq@permanentcycle\else\pgfkeysalso{/sseqpages/class/.cd,#1}\fi}, + class/transient cycles/.code={\ifsseq@permanentcycle\else\pgfkeysalso{/sseqpages/class/.cd,#1}\fi}, + class/this page classes/.code={\ifsseq@thispage\pgfkeysalso{/sseqpages/class/.cd,#1}\fi}, + class/this page cycles/.code={\ifsseq@thispage\pgfkeysalso{/sseqpages/class/.cd,#1}\fi}, + differential/edges/.style={/sseqpages/differential/.cd,#1}, + differential/differentials/.style={/sseqpages/differential/.cd,#1}, + struct line/edges/.style={/sseqpages/struct line/.cd,#1}, + struct line/struct lines/.style={/sseqpages/struct line/.cd,#1}, + struct line/this page struct lines/.code={\ifsseq@thispage\pgfkeysalso{/sseqpages/struct line/.cd,#1}\fi}, + fit/circleclasses/.style={/sseqpages/fit/.cd,#1}, + tikz primitives/tikz primitives/.style={/sseqpages/tikz primitives/.cd,#1}, +% labels + class/class labels/.code/.expanded={\unexpanded\@xp{\sseq@collections@addtohook{/sseqpages/class/label}{\sseq@collections@classlabels@hook}{#1}}}, + class/inner class labels/.code/.expanded={\unexpanded\@xp{\sseq@collections@addtohook{/sseqpages/class/label}{\sseq@collections@innerclasslabels@hook}{#1}}}, + class/outer class labels/.code/.expanded={\unexpanded\@xp{\sseq@collections@addtohook{/sseqpages/class/label}{\sseq@collections@outerclasslabels@hook}{#1}}}, + class/pins/.code/.expanded={\unexpanded\@xp{\sseq@collections@addtohook{/sseqpages/class/label/pin}{\sseq@collections@pins@hook}{#1}}}, +% + class/labels/.code/.expanded={\unexpanded\@xp{\sseq@collections@addtohook{/sseqpages/label}{\sseq@collections@labels@hook}{#1}}}, + differential/labels/.code/.expanded={\unexpanded\@xp{\sseq@collections@addtohook{/sseqpages/label}{\sseq@collections@labels@hook}{#1}}}, + struct line/labels/.code/.expanded={\unexpanded\@xp{\sseq@collections@addtohook{/sseqpages/label}{\sseq@collections@labels@hook}{#1}}}, +% + differential/edge labels/.code/.expanded= + {\unexpanded\@xp{\sseq@collections@addtohook{/sseqpages/label}{\sseq@collections@edgelabels@hook}{#1}}}, + struct line/edge labels/.code/.expanded= + {\unexpanded\@xp{\sseq@collections@addtohook{/sseqpages/label}{\sseq@collections@edgelabels@hook}{#1}}}, + differential/differential labels/.code/.expanded= + {\unexpanded\@xp{\sseq@collections@addtohook{/sseqpages/label}{\sseq@collections@differentiallabels@hook}{#1}}}, + struct line/struct line labels/.code/.expanded= + {\unexpanded\@xp{\sseq@collections@addtohook{/sseqpages/label}{\sseq@collections@structlinelabels@hook}{#1}}}, +} + + + + %%% Global keys handlers and infrastructure \def\sseq@keys@lastpart{% @@ -909,6 +1039,50 @@ \edef\sseq@temp@ii{\pgfkeyscurrentkey}% } +\def\sseq@sanitize@intexpr#1#2{ + \sseq@ifintexpr{#1}{ + \edef\sseq@sanitize@output{\the\numexpr#1} + }{ + \sseq@error@xx{invalid-intexpr}{\unexpanded{#2}}{#1} + \sseq@break + } +} + +\def\sseq@sanitize@positiveintexpr#1#2{ + \sseq@sanitize@intexpr{#1}{#2} + \ifnum\sseq@sanitize@output<1\relax + \sseq@error@xx{invalid-positive-intexpr}{\unexpanded{#2}}{#1} + \@xp\sseq@break + \fi +} + +\def\sseq@sanitize@dimenexpr#1#2{ + \sseq@ifpgfmathexpr{#1}{ + \ifpgfmathunitsdeclared\else + \sseq@error@xx{invalid-dimenexpr}{\unexpanded{#2}}{#1} + \@xp\sseq@break + \fi + \edef\sseq@sanitize@output{\sseq@mathresult} + }{ + \sseq@error@xx{invalid-dimenexpr}{\unexpanded{#2}}{#1} + \sseq@break + } +} + +\def\sseq@sanitize@color#1#2{ + \begingroup + \global\sseq@gtempiffalse + \def\c@lor@error##1{\global\sseq@gtempiftrue} + \color{#1} + \endgroup + \ifsseq@gtempif + \sseq@error@xx{invalid-color}{\unexpanded{#2}}{#1} + \@xp\sseq@break + \else + \def\sseq@sanitize@output{#1} + \fi +} + \pgfqkeys{/handlers}{ .sseq store in/.code 2 args={% \sseq@addtostorelist#1{#2}% @@ -918,6 +1092,44 @@ /sseqpages/global/default/\sseq@temp/.store in/.expand once=\csname \sseq@macroname#1@default\endcsname }% }, + .sseq store in sanitize/.code n args={3}{% + \sseq@addtostorelist#1{#2}% + \sseq@keys@lastpart + \pgfkeys{% + \sseq@temp@ii/.code/.expanded={% + \unexpanded{#3{##1}}{\sseq@temp=\unexpanded{##1}}% + \unexpanded{\edef#1{\unexpanded\@xp{\sseq@sanitize@output}}}% + %\show\@nx#1 + \sseq@breakpoint + }, + \sseq@temp@ii/.value required, + /sseqpages/global/default/\sseq@temp/.code/.expanded={% + \unexpanded{#3{##1}}{\sseq@temp=\unexpanded{##1}}% + \edef\@xp\@nx\csname \sseq@macroname#1@default\endcsname\unexpanded{{\unexpanded\@xp{\sseq@sanitize@output}}}% + \sseq@breakpoint + }, + /sseqpages/global/default/\sseq@temp/.value required + }% + + }, + .sseq store int in/.code 2 args={ + \sseq@keys@lastpart + \pgfkeysalso{% + \sseq@temp@ii/.sseq store in sanitize={#1}{#2}\sseq@sanitize@intexpr + } + }, + .sseq store positive int in/.code 2 args={ + \sseq@keys@lastpart + \pgfkeysalso{% + \sseq@temp@ii/.sseq store in sanitize={#1}{#2}\sseq@sanitize@positiveintexpr + } + }, + .sseq store dimen in/.code 2 args={ + \sseq@keys@lastpart + \pgfkeysalso{% + \sseq@temp@ii/.sseq store in sanitize={#1}{#2}\sseq@sanitize@dimenexpr + } + }, .sseq append to style/.code 2 args={% \sseq@addkeytostorelist{#1}{\pgfkeysalso{#2}}% \sseq@keys@lastpart @@ -970,8 +1182,8 @@ \sseq@usedparam\sseq@tempb \fi \pgfkeys{% - /sseqpages/global/\sseq@temp/.ecode={\@nx\pgfkeysalso{\sseq@tempb{x}={##1},\sseq@tempb{y}={##1}}},% - /sseqpages/global/default/\sseq@temp/.ecode={\@nx\pgfkeysalso{\sseq@tempb{x}={##1},\sseq@tempb{y}={##1}}}% + /sseqpages/global/\sseq@temp/.code/.expanded={\@nx\pgfkeysalso{\sseq@tempb{x}=\unexpanded{{##1}},\sseq@tempb{y}=\unexpanded{{##1}}}},% + /sseqpages/global/default/\sseq@temp/.code/.expanded={\@nx\pgfkeysalso{\sseq@tempb{x}=\unexpanded{{##1}},\sseq@tempb{y}=\unexpanded{{##1}}}}% }% } } @@ -987,32 +1199,35 @@ } } -\def\sseq@add@tikzkey@to@options@forstylehander#1{\sseq@e@addto@options{\@nx\sseq@options@secondpass{#1}}} +\def\sseq@patchrepeat#1#2#3{% + \patchcmd#1{#2}{#3}{\sseq@patchrepeat{#1}{#2}{#3}}{}% +} + +\def\sseq@stylehandler@processpath#1#2{% + \def\sseq@savedoptioncode{}% + \sseq@eval{\@nx\sseq@addstylecodetooptions{/sseqpages/#1}{\unexpanded\@xp{\sseq@keybody{*1}}}}% + \edef\sseq@savedoptioncode##1{\unexpanded\@xp{\sseq@savedoptioncode}}% + \sseq@patchrepeat\sseq@savedoptioncode{*1}{##1}% + \sseq@eval{\@nx\pgfqkeys{/sseqpages/#1}{\sseq@temp/.#2={\unexpanded\@xp{\sseq@savedoptioncode{##1}}}}}% +} + +\def\sseq@add@tikzkey@to@options@forstylehander#1{\sseq@e@addto@options{#1}} \pgfqkeys{/handlers}{ % defines sseq style, etc sseq @@ make style handler/.style 2 args={% .sseq #1/.code={% + \def\sseq@keybody####1{##1}% \sseq@keys@lastpart \let\sseq@savedoptioncode@store\sseq@savedoptioncode \def\sseq@keys@unknown@error{}% - \def\sseq@savedoptioncode{}% \let\sseq@add@tikzkey@to@options\sseq@add@tikzkey@to@options@forstylehander - \sseq@addstylecodetooptions{/sseqpages/scope}{##1}% - \sseq@eval{\@nx\pgfkeys{/sseqpages/scope/\sseq@temp/.#2={\unexpanded\@xp{\sseq@savedoptioncode}}}}% - \def\sseq@savedoptioncode{}% - \sseq@addstylecodetooptions{/sseqpages/class}{##1}% - \sseq@eval{\@nx\pgfkeys{/sseqpages/class/\sseq@temp/.#2={\unexpanded\@xp{\sseq@savedoptioncode}}}}% - \def\sseq@savedoptioncode{}% - \sseq@addstylecodetooptions{/sseqpages/differential}{##1}% - \sseq@eval{\@nx\pgfkeys{/sseqpages/differential/\sseq@temp/.#2={\unexpanded\@xp{\sseq@savedoptioncode}}}}% - \def\sseq@savedoptioncode{}% - \sseq@addstylecodetooptions{/sseqpages/struct line}{##1}% - \sseq@eval{\@nx\pgfkeys{/sseqpages/struct line/\sseq@temp/.#2={\unexpanded\@xp{\sseq@savedoptioncode}}}}% - \def\sseq@savedoptioncode{}% - \sseq@addstylecodetooptions{/sseqpages/circle classes}{##1} - \sseq@eval{\@nx\pgfkeys{/sseqpages/circle classes/\sseq@temp/.#2={\unexpanded\@xp{\sseq@savedoptioncode}}}}% - \def\sseq@savedoptioncode{}% - \sseq@addstylecodetooptions{/sseqpages/tikz primitives}{##1}% - \sseq@eval{\@nx\pgfkeys{/sseqpages/tikz primitives/\sseq@temp/.#2={\unexpanded\@xp{\sseq@savedoptioncode}}}}% +% + \sseq@stylehandler@processpath{scope}{#2}% + \sseq@stylehandler@processpath{class}{#2}% + \sseq@stylehandler@processpath{differential}{#2}% + \sseq@stylehandler@processpath{struct line}{#2}% + \sseq@stylehandler@processpath{circle classes}{#2}% + \sseq@stylehandler@processpath{tikz primitives}{#2}% +% \let\sseq@savedoptioncode\sseq@savedoptioncode@store \let\sseq@addstylecodetooptions@unknown\sseq@keys@unknown \let\sseq@keys@unknown@error\sseq@keys@unknown@error@normal @@ -1036,7 +1251,7 @@ sseq @@ make code handler=code, sseq @@ make code handler=prefix code, sseq @@ make code handler=append code, -% +% these just are the same as /.style, etc. .global sseq style/.code={\pgfkeys{\pgfkeyscurrentpath/.code=\pgfkeysalso{#1}}}, .global sseq prefix style/.code={\pgfkeys{\pgfkeyscurrentpath/.add code={\pgfkeysalso{#1}}{}}}, .global sseq append style/.code={\pgfkeys{\pgfkeyscurrentpath/.add code={}{\pgfkeysalso{#1}}}}, @@ -1147,11 +1362,19 @@ name/.sseq default error, ~page/.code={ \ifsseq@hasname - \sseq@ifintexpr{#1}{ - \def\sseq@thepage{#1}\sseq@thepagecount=#1\relax\let\page\sseq@thepage - }{ - \sseq@error{invalid-page}{#1} - } + \sseq@getnumrange\sseq@thepage{#1} + \sseq@thepagecount=\sseq@thepage\relax + \let\page\sseq@thepage + \edef\sseq@thepagemm{\the\numexpr\sseq@thepagecount-1\relax} + \ifx\sseq@thepagemax\undefined + \edef\sseq@thepagemaxpp{\the\numexpr\sseq@thepagecount+1\relax} + \else + \ifnum\sseq@thepagemax=\z@ + \let\sseq@thepagemaxpp\sseq@infinity + \else + \edef\sseq@thepagemaxpp{\the\numexpr\sseq@thepagemax+1\relax} + \fi + \fi \else \sseq@error{page-no-name} \fi @@ -1168,6 +1391,11 @@ }, grid/.code={\ifcsname sseq@grid@#1\endcsname\@xp\let\@xp\sseq@grid\csname sseq@grid@#1\endcsname\else\sseq@error@n{unknown-grid}{#1}\fi}, grid/.sseq default code={\ifcsname sseq@grid@#1\endcsname\@xp\let\@xp\sseq@grid@default\csname sseq@grid@#1\endcsname\else\sseq@error@n{unknown-grid}{#1}\fi}, + grid color/.sseq store in sanitize=\sseq@gridcolor{gray}\sseq@sanitize@color, + grid step/.sseq x y alias, + grid step/.value required, + x grid step/.sseq store positive int in=\sseq@xgridstep{1}, + y grid step/.sseq store positive int in=\sseq@ygridstep{1}, math nodes/.sseq is if=mathnodes, % TODO: make this locally toggleable custom clip/.sseq store in=\sseq@customclip{}, clip/.sseq is if=clip, @@ -1178,7 +1406,7 @@ draw orphan edges/.sseq is if=draworphanedges, no orphan edges/.sseq is if false={draworphanedges}, class pattern/.sseq store in=\sseq@classpattern{standard}, - class pattern/.append code={\ifcsname sseq@\sseq@classpattern xoffset1/1\endcsname\else\sseq@error{unknown-class-pattern}\fi}, + class pattern/.add code={\ifcsname sseq@#1xoffset1/1\endcsname\else\sseq@error{unknown-class-pattern}\@xp\sseq@break\fi}{\sseq@breakpoint}, class placement transform/.code={% \bgroup \let\tikz@transform\pgfutil@empty @@ -1218,8 +1446,6 @@ \sseq@addtostorelist\sseq@classplacementtransform{} -\sseq@addiftostorelist@truedefault{borderxaxis}\sseq@addiftostorelist@truedefault{borderyaxis} -\sseq@addtostorelist\sseq@xaxisorigin{0}\sseq@addtostorelist\sseq@yaxisorigin{0} %%% Range keys and commands \sseq@globalkeys{% @@ -1249,18 +1475,27 @@ \@xp\sseq@addtostorelist\@xp\sseq@xmaxpp\@xp{\sseq@infinity} \@xp\sseq@addtostorelist\@xp\sseq@ymaxpp\@xp{\sseq@infinity} +\sseq@addiftostorelist{specifiedxrange} +\sseq@addiftostorelist{specifiedyrange} \def\sseq@xrange#1#2{% \global\let\sseq@xminmax\@gobbletwo % Don't need to calculate range of nodes if user specifies it - \gdef\sseq@xmin{#1}% - \gdef\sseq@xmax{#2}% + \global\sseq@specifiedxrangetrue + \sseq@sanitize@intexpr{#1}{x range={#1}{#2}} + \sseq@sanitize@intexpr{#2}{x range={#1}{#2}} + \xdef\sseq@xmin{\the\numexpr#1}% + \xdef\sseq@xmax{\the\numexpr#2}% \let\xmin\sseq@xmin \let\xmax\sseq@xmax % Need to know decremented \xmin and incremented \xmax to decide which nodes to print \sseq@tempcount=#1 \advance\sseq@tempcount-1\xdef\sseq@xminmm{\the\sseq@tempcount}% \sseq@tempcount=#2 \advance\sseq@tempcount1\xdef\sseq@xmaxpp{\the\sseq@tempcount}% + \sseq@breakpoint } \def\sseq@yrange#1#2{% \global\let\sseq@yminmax\@gobbletwo % + \sseq@sanitize@intexpr{#1}{x range={#1}{#2}} + \sseq@sanitize@intexpr{#2}{x range={#1}{#2}} + \global\sseq@specifiedyrangetrue \gdef\sseq@ymin{#1}% \gdef\sseq@ymax{#2}% \let\ymin\sseq@ymin @@ -1340,6 +1575,7 @@ %%% Axes and Layout options \sseq@addtostorelist{\sseq@xtickfn}{} % These should initially be the identity macro, but addtostorelist doesn't accept functions as default \sseq@addtostorelist{\sseq@ytickfn}{} % so the default is instated in begin{sseqdata} / begin{sseqpicture}. + \sseq@globalkeys{% title/.sseq store in=\sseq@title{}, title style/.sseq append to style={/sseqpages/global/every title}{at={(0.5*\xmin+0.5*\xmax,\ymax)}}, @@ -1358,13 +1594,9 @@ no labels/.sseq x y alias=no #1 label, draw labels/.sseq x y alias=draw #1 label, % - no x axis/.sseq is if false={drawxaxis}, - no y axis/.sseq is if false={drawyaxis}, - no axes/.value forbidden, - no axes/.sseq x y alias=no #1 axis, - draw x axis/.sseq is if=drawxaxis, - draw y axis/.sseq is if=drawyaxis, - draw axes/.sseq x y alias=draw #1 axis, + no x axis/.style={x axis type=none}, + no y axis/.style={y axis type=none}, + no axes/.style={axes type=none}, rotate labels/.sseq is if=rotatelabels, % draw x ticks/.sseq is if=drawxaxisticks, @@ -1377,62 +1609,135 @@ draw ticks/.default=true, tick step/.sseq x y alias, tick step/.value required, - x tick step/.sseq store in=\sseq@xtickstep{1}, - y tick step/.sseq store in=\sseq@ytickstep{1}, + x tick step/.sseq store positive int in=\sseq@xtickstep{1}, + y tick step/.sseq store positive int in=\sseq@ytickstep{1}, + tick offset/.sseq x y alias, + tick offset/.value required, + x tick offset/.sseq store int in=\sseq@xtickstepoffset{0}, + y tick offset/.sseq store int in=\sseq@ytickstepoffset{0}, + major tick step/.sseq x y alias, + x major tick step/.sseq store int in=\sseq@xmajortickstep{0}, + y major tick step/.sseq store int in=\sseq@ymajortickstep{0}, + minor tick step/.sseq x y alias, + x minor tick step/.sseq store int in=\sseq@xminortickstep{0}, + y minor tick step/.sseq store int in=\sseq@yminortickstep{0}, x tick handler/.code={\def\sseq@xtickfn##1{#1}}, x tick handler/.sseq default code={\def\sseq@xtickfn@default##1{#1}}, y tick handler/.code={\def\sseq@ytickfn##1{#1}}, y tick handler/.sseq default code={\def\sseq@ytickfn@default##1{#1}}, - class label handler/.code = {\long\def\sseq@classlabeltextfn##1{#1}}, % \long so that \ifx\classlabeltextfn\@gobble compares true if this is empty (\@gobble is long...) - class label handler/.sseq default code={\long\def\sseq@classlabeltextfn@default##1{#1}}, + class label handler/.code = { % \long so that \ifx\classlabeltextfn\@gobble compares true if this is empty (\@gobble is long...) + \long\def\sseq@classlabeltextfn##1{#1} + \ifx\sseq@classlabeltextfn\@gobble + \def\sseq@classlabeltextfn##1{\def\processedlabel{##1}} + \else + \edef\sseq@tempa{\unexpanded\@xp{\sseq@classlabeltextfn{}}} + \edef\sseq@tempb{\unexpanded\@xp{\sseq@classlabeltextfn{blah}}} + \ifx\sseq@tempa\sseq@tempb + \long\def\sseq@classlabeltextfn##1{#1{##1}} + \fi + \fi + }, + class label handler/.sseq default code={ + \long\def\sseq@classlabeltextfn@default##1{#1} + \ifx\sseq@classlabeltextfn@default\@gobble + \def\sseq@classlabeltextfn@default##1{\def\processedlabel{##1}} + \else + \edef\sseq@tempa{\unexpanded\@xp{\sseq@classlabeltextfn@default{}}} + \edef\sseq@tempb{\unexpanded\@xp{\sseq@classlabeltextfn@default{blah}}} + \ifx\sseq@tempa\sseq@tempb + \long\def\sseq@classlabeltextfn@default##1{#1{##1}} + \fi + \fi + }, x tick style/.sseq store in=\sseq@xtickstyle{}, y tick style/.sseq store in=\sseq@ytickstyle{}, tick style/.sseq x y alias, % - x axis style/.is choice, - y axis style/.is choice, - axes style/.sseq x y alias=axis style, - ~x axis style/border/.code={\sseq@drawxaxistrue\sseq@borderxaxistrue}, - ~y axis style/border/.code={\sseq@drawyaxistrue\sseq@borderyaxistrue}, - ~x axis style/center/.code={ - \sseq@drawxaxistrue\sseq@borderxaxisfalse - \ifx\sseq@xaxisgap\sseq@xaxisgap@default - \def\sseq@xaxisgap{0cm} - \fi - }, - ~y axis style/center/.code={\sseq@drawyaxistrue\sseq@borderyaxisfalse\ifx\sseq@yaxisgap\sseq@yaxisgap@default\def\sseq@yaxisgap{0cm}\fi}, - ~x axis style/none/.code={\sseq@drawxaxisfalse}, - ~y axis style/none/.code={\sseq@drawyaxisfalse}, - x axis origin/.sseq store in=\sseq@xaxisorigin{0}, - y axis origin/.sseq store in=\sseq@yaxisorigin{0}, + axes type/.sseq x y alias=axis type, + axes type/.add code={\let\sseq@axistypesanitizer\sseq@axistypesanitizerb}{\let\sseq@axistypesanitizer\sseq@axistypesanitizera}, + axes type/.value required, + x axis type/.sseq store in sanitize=\sseq@xaxistype{border}\sseq@axistypesanitizer, + x axis type/.value required, + y axis type/.sseq store in sanitize=\sseq@yaxistype{border}\sseq@axistypesanitizer, + y axis type/.value required, + x axis origin/.sseq store int in=\sseq@xaxisorigin@center@{0}, + y axis origin/.sseq store int in=\sseq@yaxisorigin@center@{0}, axes origin/.sseq x y alias=axis origin, } + +\def\sseq@validaxestypesa{border, center, or none. The value frame only works with the 'axes type' key.} +\def\sseq@validaxestypesb{border, center, frame, or none.} +\let\sseq@validaxestypes\sseq@validaxestypesa + +\let\sseq@axistypekeya\@firstofone +\def\sseq@axistypekeyb#1{axes type} +\let\sseq@axistypekey\sseq@axistypekeya + +\def\sseq@uptoequal#1{\sseq@uptoequal@#1\sseq@nil} +\def\sseq@uptoequal@#1=#2\sseq@nil{#1} +\def\sseq@axistypesanitizerb#1#2{ + \let\sseq@validaxestypes\sseq@validaxestypesb + \let\sseq@axistypekey\sseq@axistypekeyb + \@xp\ifx\csname sseq@leftgridpadding@y#1\endcsname\relax + \sseq@error@xx{invalid-axis-type}{#1}{\sseq@uptoequal{#2}} + \sseq@breakfi + \else + \def\sseq@sanitize@output{#1} + \fi + \let\sseq@validaxestypes\sseq@validaxestypesa + \let\sseq@axistypekey\sseq@axistypekeya +} + +\def\sseq@axistype@frame{frame} +\def\sseq@axistypesanitizera#1#2{ + \def\temp{#1} + \ifx\sseq@axistype@frame\temp + \sseq@error@xx{invalid-axis-type}{#1}{\sseq@uptoequal{#2}} + \sseq@breakfi + \fi + \sseq@axistypesanitizerb{#1}{#2} +} +\let\sseq@axistypesanitizer\sseq@axistypesanitizera + \pgfqkeys{/sseqpages}{% - class label handler/.code = {\long\def\sseq@classlabeltextfn##1{#1}} + class label handler/.code = { % \long so that \ifx\classlabeltextfn\@gobble compares true if this is empty (\@gobble is long...) + \long\def\sseq@classlabeltextfn##1{#1} + \ifx\sseq@classlabeltextfn\@gobble + \def\sseq@classlabeltextfn##1{\def\processedlabel{##1}} + \else + \edef\sseq@tempa{\unexpanded\@xp{\sseq@classlabeltextfn{}}} + \edef\sseq@tempb{\unexpanded\@xp{\sseq@classlabeltextfn{blah}}} + \ifx\sseq@tempa\sseq@tempb + \long\def\sseq@classlabeltextfn##1{#1{##1}} + \fi + \fi + } } \sseq@globalkeys{ axes gap/.sseq x y alias=axis gap, axes gap/.value required, - x axis gap/.sseq store in=\sseq@xaxisgap{0.5cm}, - y axis gap/.sseq store in=\sseq@yaxisgap{0.5cm}, + x axis gap/.sseq store dimen in=\sseq@xaxisgap{0.5cm}, + y axis gap/.sseq store dimen in=\sseq@yaxisgap{0.5cm}, tick gap/.sseq x y alias, tick gap/.value required, - x tick gap/.sseq store in=\sseq@xlabelgap{0.5cm}, - y tick gap/.sseq store in=\sseq@ylabelgap{0.5cm}, - x axis extend start/.sseq store in=\sseq@xaxis@start@extend{0.9cm}, - y axis extend start/.sseq store in=\sseq@yaxis@start@extend{0.9cm}, + x tick gap/.sseq store dimen in=\sseq@xlabelgap{0.5cm}, + y tick gap/.sseq store dimen in=\sseq@ylabelgap{0.5cm}, + x axis tail/.sseq store dimen in=\sseq@xaxis@tail{0.9cm}, + y axis tail/.sseq store dimen in=\sseq@yaxis@tail{0.9cm}, + x axis extend start/.sseq store dimen in=\sseq@xaxis@start@extend{0.5cm}, + y axis extend start/.sseq store dimen in=\sseq@yaxis@start@extend{0.5cm}, axes extend start/.sseq x y alias=axis extend start, - x axis extend end/.sseq store in=\sseq@xaxis@end@extend{0.5cm}, - y axis extend end/.sseq store in=\sseq@yaxis@end@extend{0.5cm}, + x axis extend end/.sseq store dimen in=\sseq@xaxis@end@extend{0.5cm}, + y axis extend end/.sseq store dimen in=\sseq@yaxis@end@extend{0.5cm}, axes extend end/.sseq x y alias=axis extend end, - x axis clip padding/.sseq store in=\sseq@xclip@axisgap{0.1cm}, - y axis clip padding/.sseq store in=\sseq@yclip@axisgap{0.1cm}, + x axis clip padding/.sseq store dimen in=\sseq@xclip@axisgap{0.1cm}, + y axis clip padding/.sseq store dimen in=\sseq@yclip@axisgap{0.1cm}, axes clip padding/.sseq x y alias=axis clip padding, - right clip padding/.sseq store in=\sseq@clip@padding@right{0.1cm}, - left clip padding/.sseq store in=\sseq@clip@padding@left{0.4cm}, - top clip padding/.sseq store in=\sseq@clip@padding@top{0.1cm}, - bottom clip padding/.sseq store in=\sseq@clip@padding@bottom{0.4cm} + right clip padding/.sseq store dimen in=\sseq@clip@padding@right{0.1cm}, + left clip padding/.sseq store dimen in=\sseq@clip@padding@left{0.1cm}, + top clip padding/.sseq store dimen in=\sseq@clip@padding@top{0.1cm}, + bottom clip padding/.sseq store dimen in=\sseq@clip@padding@bottom{0.1cm} } %%% @@ -1445,6 +1750,9 @@ \sseq@addtostorelist\sseq@globalrotatetransform{} \sseq@addtostorelist\sseq@globalscaletransform{} +\sseq@addtostorelist\sseq@xscale{1} +\sseq@addtostorelist\sseq@yscale{1} + \def\sseq@globaldetoneoption#1#2{% \ifsseq@globaldetone\else \sseq@error@n{det-one-after-scale}{#2} @@ -1454,7 +1762,7 @@ } \def\sseq@globalscaleoption#1{% \sseq@globaldetonefalse - \@xp\gdef\@xp\sseq@globalscaletransform\@xp{\sseq@globalscaletransform#1}#1% + \@xp\gdef\@xp\sseq@globalscaletransform\@xp{\sseq@globalscaletransform#1}% } \pgfqkeys{/sseqpages/global}{% x/.sseq @ illegal, @@ -1481,28 +1789,44 @@ mirror/.forward to=/sseqpages/global/xmirror, mirror/.forward to=/sseqpages/global/ymirror, xscale/.code={% - \pgfmathparse{int(#1-1)}% - \ifnum\pgfmathresult<\z@% + \sseq@ifpgfmathexpr{int(#1-1)}{}{ + \sseq@error@nn{invalid-scale}{x}{#1}% + \sseq@break + } + \ifpgfmathunitsdeclared + \sseq@error@nn{unit-scale}{x}{#1}% + \sseq@break + \fi + \ifnum\sseq@mathresult<\z@ \sseq@error@nn{negative-scale}{x}{#1}% + \sseq@break \fi - \sseq@globalscaleoption{\pgftransformxscale{#1}}% + \sseq@globalscaleoption{\pgfsetxvec{\pgfpointxy{#1}{0}}} + \pgfmathparse{\sseq@xscale*#1} + \edef\sseq@xscale{\pgfmathresult} + \sseq@breakpoint }, xscale/.value required, yscale/.code={% - \pgfmathparse{int(#1-1)}% - \ifnum\pgfmathresult<\z@ + \sseq@ifpgfmathexpr{int(#1-1)}{}{ + \sseq@error@nn{invalid-scale}{y}{#1}% + \sseq@break + } + \ifpgfmathunitsdeclared + \sseq@error@nn{unit-scale}{y}{#1}% + \sseq@break + \fi + \ifnum\sseq@mathresult<\z@ \sseq@error@nn{negative-scale}{y}{#1}% + \sseq@break \fi - \sseq@globalscaleoption{\pgftransformyscale{#1}}% + \sseq@globalscaleoption{\pgfsetyvec{\pgfpointxy{0}{#1}}} + \pgfmathparse{\sseq@yscale*#1} + \edef\sseq@yscale{\pgfmathresult} + \sseq@breakpoint }, yscale/.value required, - scale/.code={% - \pgfmathparse{int(#1-1)}% - \ifnum\pgfmathresult<\z@ - \sseq@error@nn{negative-scale}{}{#1}% - \fi - \sseq@globalscaleoption{\pgftransformscale{#1}}% - }, + scale/.sseq x y alias=#1scale, scale/.value required } @@ -1520,11 +1844,11 @@ x/.code={\sseq@error@n{option-illegal}{#1}}, y/.code={\sseq@error@n{option-illegal}{#1}}, z/.code={\sseq@error@n{option-illegal}{#1}}, - xshift/.sseq @ second pass code={\sseq@shifttransform{x}{#1}}, % I don't know why it has to be this way, - xshift/.sseq @ first pass append code={\sseq@firstpass@shifttransform{x}{#1}}, % but it definitely breaks if I change it... + xshift/.sseq @ first pass code=\sseq@tikz@firstpass@checkshifttransform{x}{#1}, + yshift/.sseq @ first pass code=\sseq@tikz@firstpass@checkshifttransform{y}{#1}, + xshift/.append code=\sseq@options@scopeshiftsecondpass{\sseq@tikz@shifttransform{x}{#1}},%% Note special scopeshiftsecondpass command + yshift/.append code=\sseq@options@scopeshiftsecondpass{\sseq@tikz@shifttransform{y}{#1}},%% xshift/.value required, - yshift/.sseq @ second pass code={\sseq@shifttransform{y}{#1}}, - yshift/.sseq @ first pass append code={\sseq@firstpass@shifttransform{y}{#1}}, yshift/.value required, shift/.sseq @ transform, shift/.value required, shift only/.sseq @ transform, @@ -1541,7 +1865,6 @@ transform canvas/.sseq @ transform, transform canvas/.value required } -% These two should be exactly the same \def\sseq@shift@firstpassprocess#1{\sseq@shift@firstpassprocess@#1\sseq@nil} \def\sseq@shift@firstpassprocess@#1#2\sseq@nil{\ifx#1\pgfpointxy\sseq@shift@firstpassprocess@@#2\else\sseq@standardparse\fi} \def\sseq@shift@firstpassprocess@@#1#2{ @@ -1556,6 +1879,15 @@ \sseq@tikz@shifttransform{y}{#2} } +% special second pass handler for scopes to prevent shifts from causing out of memory style errors, +% see the longer comment at the definition of sseq@scope in main.code.tex +\def\sseq@options@scopeshiftsecondpass{\sseq@options@secondpass} + +\sseq@pgfqkeysdirlist{/sseqpages/scope,/sseqpages/tikz primitives,/sseqpages,/sseqpages/label,/sseqpages/class/label}{ + align/.sseq @ second pass code=\tikzset{align/#1}, + align/.sseq @ first pass append code={\sseq@needstikztrue\def\sseq@classquotes@smugglehook@inner{\sseq@needstikztrue\tikzset{align/#1}}} +} + \sseq@pgfqkeysdirlist{/sseqpages/scope,/sseqpages/tikz primitives}{ shift/.code={ \sseq@options@firstpass{\tikz@scan@one@point\sseq@shift@firstpassprocess#1\relax} @@ -1563,8 +1895,8 @@ }, xshift/.sseq @ first pass code=\sseq@tikz@firstpass@checkshifttransform{x}{#1}, yshift/.sseq @ first pass code=\sseq@tikz@firstpass@checkshifttransform{y}{#1}, - xshift/.sseq @ second pass append code=\sseq@tikz@shifttransform{x}{#1}, - yshift/.sseq @ second pass append code=\sseq@tikz@shifttransform{y}{#1}, + xshift/.append code=\sseq@options@scopeshiftsecondpass{\sseq@tikz@shifttransform{x}{#1}},%% Note special scopeshiftsecondpass command + yshift/.append code=\sseq@options@scopeshiftsecondpass{\sseq@tikz@shifttransform{y}{#1}},%% rotate around/.sseq @ second pass code={\sseq@standardparse\sseq@pgfkeysdocommand{rotate}{#1}}, rotate/.sseq @ stdparse do transform, rotate/.value required, xslant/.sseq @ stdparse do transform, xslant/.value required, @@ -1589,7 +1921,7 @@ \let\sseq@firstpass@shifttransform\sseq@firstpass@checkshifttransform \def\sseq@checkshifttransform#1#2{% - \pgfmathparse{#2}% + \pgfmathparse{(#2)}% \sseq@ifpgfmathresultisunitlessint{% \@xp\pgfmathint\@xp{\pgfmathresult}% \@xp\advance\csname sseq@#1\endcsname\pgfmathresult\relax @@ -1619,7 +1951,7 @@ \sseq@ifpgfmathresultisunitlessint{% \@xp\pgfmathint\@xp{\pgfmathresult}% \@xp\advance\csname sseq@\sseq@getfirstchar#1\sseq@nil\endcsname\pgfmathresult\relax - \sseq@pgfkeysdocommand{#1shift}{#2cm} + \sseq@pgfkeysdocommand{#1shift}{#2cm*\csname sseq@#1scale\endcsname} }{ \sseq@standardparse \ifpgfmathunitsdeclared |