diff options
Diffstat (limited to 'macros/latex/contrib/assoccnt/assoccnt.sty')
-rw-r--r-- | macros/latex/contrib/assoccnt/assoccnt.sty | 613 |
1 files changed, 613 insertions, 0 deletions
diff --git a/macros/latex/contrib/assoccnt/assoccnt.sty b/macros/latex/contrib/assoccnt/assoccnt.sty new file mode 100644 index 0000000000..c22f0eb4fc --- /dev/null +++ b/macros/latex/contrib/assoccnt/assoccnt.sty @@ -0,0 +1,613 @@ + +\def\assoccntpackageversion{0.8} +\NeedsTeXFormat{LaTeX2e}% +\ProvidesPackage{assoccnt}[2015/09/29 v\assoccntpackageversion -- Associate counters stepping]% +%%% +%% License: LaTeX Project Public License version 1.3 +%% Copyright (2015) Dr. Christian Hupfer +%% Author: Christian Hupfer christian.hupfer@yahoo.de +%% +%%%% + + +\def\@@assoccnt@@keys{assoccntkeyfamily}% + +\def\@@assoccnt@@packagename{assoccnt.sty}% +\def\@@assoccnt@@keyprefix{@@assoccnt@@pkg@@}% + +\typeout{\@@assoccnt@@packagename{} -- version v\assoccntpackageversion} + + +\RequirePackage{xcolor}% +\RequirePackage{etoolbox}[2011/01/03 2.2]% +\RequirePackage{xkeyval}[2012/10/14 v2.6b]% +\RequirePackage{xstring}% + +\newif\if@calcpackage + +\@ifpackageloaded{calc}{% +\@calcpackagetrue% +}{% +\@calcpackagefalse% +} + + +%%%% Defining package options + +\newtoggle{GlobalSuspend}% +\settoggle{GlobalSuspend}{false}% + + +% Option for enabling the global suspend facility for an arbitray counters +\define@boolkey{\@@assoccnt@@packagename}[@@assoccnt@@pkg@@]{globalsuspend}[false]{% + \if@@assoccnt@@pkg@@globalsuspend% + \toggletrue{GlobalSuspend}% + \else% + \togglefalse{GlobalSuspend}% + \fi% +}% + +\DeclareOptionX*{\PackageWarning{\@@assoccnt@@packagename}{Option '\CurrentOption ' ignored}}% + + +\ProcessOptionsX% + +%%%%% + + + +\newcounter{@@assoccnt@@internalcounter}% + + +\gdef\@@assoccnt@@storagemacro@@laststeppedcounter{}% +\gdef\@@assoccnt@@storagemacro@@lastrefsteppedcounter{}% +\gdef\@@assoccnt@@storagemacro@@lastaddtocounter{}% +\gdef\@@assoccnt@@storagemacro@@lastsetcounter{}% + + +\let\@@assoccnt@@standardaddtocounter\addtocounter% +\let\@@assoccnt@@standardstepcounter\stepcounter% +\let\@@assoccnt@@standardrefstepcounter\refstepcounter% +\let\@@assoccnt@@standardsetcounter\setcounter% + + + +% Unused so far +\newcommand{\IsInResetList}[4]{% + \IfSubStr{\csname cl@#1\endcsname}{{#2}}{% Mind the {} around the #2 parameter! + #3% + }{% + #4% + }% +} + + +% Just for a quick suffix +\newcommand{\@@assoccnt@@associatedcounterslistsuffix}{% +AssociatedCountersList% +}% + + + +%%% Internal macro to generate the name of the list of associated counters +\newcommand{\@@assoccnt@@generatelistname}[1]{% +% #1 Name of the driver counter + @@#1@@\@@assoccnt@@associatedcounterslistsuffix% +}% + +\newcommand{\@@assoccnt@@drivercounterlist}{% +@@assoccnt@@DriverCountersList% +}% + +%% +%% Adds a driver counter to an internal administration list +\newcommand{\AddDriverCounter}[2][]{% +% #1 -> options +% #2 -> driver counter name + \setkeys{\@@assoccnt@@keys}{#1}% + \ifcsdef{\@@assoccnt@@drivercounterlist}{% + }{% + \csgdef{\@@assoccnt@@drivercounterlist}{}% + }% + \listcsgadd{\@@assoccnt@@drivercounterlist}{#2}% +}% + + +%% +%% Removes the complete list of driver counters +\newcommand{\ClearDriverCountersList}{% + \ifcsdef{\@@assoccnt@@drivercounterlist}% + {% + % Clear the possible driver counter entry in the list, the trailing associated counters list + % is cleared as well + \forlistcsloop{\ClearAssociatedCountersList}{\@@assoccnt@@drivercounterlist}% + }{% + % Nothing to be done + }% +}% + +\newcommand{\IsDriverCounter}[3]{% + \ifcsdef{\@@assoccnt@@drivercounterlist}{% + \ifinlistcs{#1}{\@@assoccnt@@drivercounterlist}{% True branch, it's in the list + #2% + }{% False branch, not in the list + #3% + }% + }{% List does not exist at all --> expand false branch + #3% + }% +}% + +\newcommand{\@@assoccnt@@generateboundtocounterslist}[1]{% +#1@@boundtocounterslist% +}% + + +\newcommand{\@@assoccnt@@addassociatedcounter}[3][]{% + \ifcsdef{#2}{% + % driver counter list exists, check, whether it is already there + \ifinlistcs{#3}{#2}{% + % Do nothing, since counter is already in the list, prevent multiple list insertion + }{% + \listcsgadd{#2}{#3}% + \listcsgadd{\@@assoccnt@@generateboundtocounterslist{#3}}{#1} + }% + }{% + \listcsgadd{\@@assoccnt@@generatelistname{#1}}{#3}% + \listcsgadd{\@@assoccnt@@generateboundtocounterslist{#3}}{#1}% + }% +}% + + + + + +\newcommand{\AddAssociatedCounters}[3][]{% +% #1 --> options +% #2 --> driver counter +% #3 --> CSV list of counters, that should be stepped, if the driver counter is stepped + \setkeys{\@@assoccnt@@keys}{#1}% + \ifcsdef{\@@assoccnt@@generatelistname{#2}}{% + % % Nothing to be done --> List already exists + \forcsvlist{\@@assoccnt@@addassociatedcounter[#2]{\@@assoccnt@@generatelistname{#2}}}{#3}% + % Prevent accidental self - association + \RemoveAssociatedCounter{#2}{#2}% + }{% + \GenericError{}{Error: List for driver counter #2 does not exist -- Usage on line \the\inputlineno}{}{} + }% +}% + +% This command defines a list of counters, that should be stepped also if the driver counter +% is `\stepcounter`ed. +% A self - association is not possible, as this would lead to inconsistent counting +\newcommand{\DeclareAssociatedCounters}[3][]{% +% #1 --> options +% #2 --> driver counter +% #3 --> CSV list of other counters, that should be stepped, if the driver counter is stepped + \setkeys{\@@assoccnt@@keys}{#1}% + \ifcsdef{\@@assoccnt@@generatelistname{#2}}{% + % % Nothing to be done --> List already exists + \GenericWarning{}{Warning: List of associated counters for driver counter #2 already exists}% + }{% + \AddDriverCounter{#2}% + \listcsgadd{\@@assoccnt@@generatelistname{#2}}{}% Define some global list + }% + % Now add the counter names from #3 to the list + % Note: Currently, it is not checked whether a counter is already added! + \forcsvlist{\@@assoccnt@@addassociatedcounter[#2]{\@@assoccnt@@generatelistname{#2}}}{#3}% + % Now remove an accidental self-association + \RemoveAssociatedCounter{#2}{#2}% +}% + +% Later on +%\@onlypreamble{\DeclareAssociatedCounters}% + + +%% + + + + +\newcommand{\@@assoccnt@@copylist}[2]{% + \ifstrequal{#1}{#2}{% + % Nothing to be done + }{% + \csundef{#2}% + \renewcommand*{\do}[1]{% + \listcsgadd{#2}{##1}% + }% + \dolistcsloop{#1}% + }% +}% + + + +%%% A generic macro, that removes a list entry from the list by +%%% defining a temporary list and omitting the +\newcommand{\@@assoccnt@@removefromlist}[2]{% +% #1 list name +% #2 element to be removed + \ifcsdef{#1}{% + \ifcsdef{@@assoccnt@@templist}{% + \csundef{@@assoccnt@@templist}% + }{}% + \listcsgadd{@@assoccnt@@templist}{}% + \@@assoccnt@@standardsetcounter{@@assoccnt@@internalcounter}{0}% + \renewcommand*{\do}[1]{% + \ifstrequal{##1}{#2}{% + % Later one some success routine etc. ??? + }{% + \listcsgadd{@@assoccnt@@templist}{##1}% + \@@assoccnt@@standardstepcounter{@@assoccnt@@internalcounter}% + }% + }% + \dolistcsloop{#1}% + \csundef{#1}% + \ifnumgreater{\number\value{@@assoccnt@@internalcounter}}{0}{% + \@@assoccnt@@copylist{@@assoccnt@@templist}{#1}% + }{}% + }{% + % The list is not defined at all, can't remove something from something not existing... + }% +}% + + + +%% Remove a particular counter from the list +\newcommand{\RemoveAssociatedCounter}[2]{% +% #1 arg: driver counter +% #2 arg: counter name to be removed + \@@assoccnt@@removefromlist{\@@assoccnt@@generatelistname{#1}}{#2}% + \@@assoccnt@@removefromlist{\@@assoccnt@@generateboundtocounterslist{#1}}{#2}% +}% + +%% Remove a CSV list of counters from the list of associated counters + +\newcommand{\RemoveAssociatedCounters}[2]{% +% #1 arg: driver counter +% #2 arg: CSV list of counters to be removed + \forcsvlist{\RemoveAssociatedCounter{#1}}{#2}% +}% + +%% Remove all associated counters from the list +\newcommand{\ClearAssociatedCountersList}[1]{% +% #1 arg: driver counter + \csundef{\@@assoccnt@@generatelistname{#1}}% + \@@assoccnt@@removefromlist{\@@assoccnt@@drivercounterlist}{#1}% +}% + + +%% Test if a counter is an associated counter of driver counter +\newcommand{\IsAssociatedToCounter}[4]{% +% #1 arg: driver counter +% #2 arg: (possibly) associated counter +% #3 arg: Code for execution on true branch +% #4 arg: Code for execution on false branch + \ifcsdef{\@@assoccnt@@generatelistname{#1}}{% + \ifinlistcs{#2}{\@@assoccnt@@generatelistname{#1}}{% + #3% + }{% + #4% + }% + }{% List does not exist, so it's not associated + #4% + }% +}% + + +\newcommand{\IsAssociatedCounter}[3]{% + \ifcsdef{\@@assoccnt@@generateboundtocounterslist{#1}}{% true branch + \@@assoccnt@@standardsetcounter{@@assoccnt@@internalcounter}{0}% + \renewcommand*{\do}[1]{% + \@@assoccnt@@standardstepcounter{@@assoccnt@@internalcounter}% + }% + \dolistcsloop{\@@assoccnt@@generateboundtocounterslist{#1}}% + \ifnumgreater{\number\value{@@assoccnt@@internalcounter}}{0}{% + #2% + }{% + #3% + }% + }{% + #3% + }% End of \ifcsdef false branch +}% + + +\newcommand{\@@assoccnt@@itemizedshowassociatedcounters}[1]{% + \begin{itemize} + \renewcommand*{\do}[1]{% + \item \@@assoccnt@@showassociatedcounterlist{##1} -- \fbox{\number\value{##1}}% + }% + \dolistcsloop{\@@assoccnt@@generatelistname{#1}}% + \end{itemize}% +}% + +\newcommand{\GeneralCounterInfoColor}{orange} +\newcommand{\DriverCounterInfoColor}{blue} +\newcommand{\AssociatedCounterInfoColor}{red} + +\define@key{\@@assoccnt@@keys}{countertype}[driver]{% + \def\@@assoccnt@@keymacro@@countertype{#1}% +}% + + +\newcommand{\PrettyPrintCounterName}[2][countertype={general}]{% + \setkeys{\@@assoccnt@@keys}{#1}% + \IfStrEq{\@@assoccnt@@keymacro@@countertype}{driver}{% + \fbox{\textcolor{\DriverCounterInfoColor}{\textbf{#2{}}}}% + }{% + \IfStrEq{\@@assoccnt@@keymacro@@countertype}{associated}{% + \fbox{\textcolor{\AssociatedCounterInfoColor}{\textbf{#2{}}}}% + }{% + \fbox{\textcolor{\GeneralCounterInfoColor}{\textbf{#2}}}% + }% + }% +}% + + +\newcommand{\AssociatedDriverCounterInfo}[1]{% + \textbf{Associated/Driver counter information on counter \PrettyPrintCounterName[countertype=general]{#1}}\par + \IsAssociatedCounter{#1}{% + Counter \PrettyPrintCounterName[countertype=associated]{#1} is associated to \PrettyPrintCounterName[countertype=driver]{\GetDriverCounter{#1}}% + \IsDriverCounter{#1}{% + Counter \PrettyPrintCounterName[countertype=driver]{#1} is driver counter of + \@@assoccnt@@itemizedshowassociatedcounters{#1}% + % + }{}% + }{% + \IsDriverCounter{#1}{% + Counter \PrettyPrintCounterName[countertype=driver]{#1} is driver counter of + \@@assoccnt@@itemizedshowassociatedcounters{#1}% + }{% + Counter \PrettyPrintCounterName[countertype=general]{#1} is neither driver nor associated counter % + }% + }% +}% + + + + + +\newcommand{\GetDriverCounter}[1]{% + \@@assoccnt@@standardsetcounter{@@assoccnt@@internalcounter}{0}% + \renewcommand*{\do}[1]{% + ##1% + \ifnumequal{\number\value{@@assoccnt@@internalcounter}}{1}{% + \listbreak}{% + \@@assoccnt@@standardstepcounter{@@assoccnt@@internalcounter}% + }% + }% + \dolistcsloop{\@@assoccnt@@generateboundtocounterslist{#1}}% +}% + +\newcommand{\@@assoccnt@@showassociatedcounterlist}[1]{% + \PrettyPrintCounterName[countertype=associated]{\textbf{#1{ }}}% +}% + +\newcommand{\@@assoccnt@@showdrivercounterlist}[1]{% + \textcolor{blue}{\textbf{#1}} + \ifcsdef{\@@assoccnt@@generatelistname{#1}}{% + \forlistcsloop{\@@assoccnt@@showassociatedcounterlist}{\@@assoccnt@@generatelistname{#1}}% + }{}% + \par% +}% + +\newcommand{\AssociationStatistics}[1][]{% + \forlistcsloop{\@@assoccnt@@showdrivercounterlist}{\@@assoccnt@@drivercounterlist}% +}% + + +\define@key{\@@assoccnt@@keys}{SuspendCounters}{% + \def\@@assoccnt@@keymacro@@suspendedcounters{#1}% + \forcsvlist{\listgadd{\@@assoccnt@@suspendedcounterslist}}{#1}% +}% + + +% A convenience macro -- do not change% +\newcommand{\@@assoccnt@@wrapperaddsuspendedcounter}[1]{% + \listcsgadd{@@assoccnt@@suspendedcounterslist}{#1}% +}% + + +\newcommand{\SuspendCounters}[2][]{% + \forcsvlist{\@@assoccnt@@wrapperaddsuspendedcounter}{#2}% +}% + +%% Not much in here +\newcommand{\ResumeSuspendedCounters}{% + \undef{\@@assoccnt@@suspendedcounterslist}% +}% + + +\newcommand{\IsSuspendedCounter}[3]{% + \ifinlistcs{#1}{@@assoccnt@@suspendedcounterslist}{% + #2% + }{% + #3% + }% +}% + + +%%% The setcounter wrapper +%\newcommand{\@@assocccnt@@setcounter}[2]{% +% \@@assoccnt@@standardsetcounter{#1}{#2}% +% \gdef\@@assoccnt@@storagemacro@@lastsetcounter{#1}% +%}% + +%%% addtocounter wrapper -- needs to switch the arguments for the command for the list usage!!! +\newcommand{\@@assocccnt@@addtocounter}[2]{% + \ifcsdef{@@assoccnt@@suspendedcounterslist}{% + % Now, there are suspended counters -- do not update them! + \IsSuspendedCounter{#2}{% + % Nothing to be done + }{% + \@@assoccnt@@standardaddtocounter{#2}{#1}% + \gdef\@@assoccnt@@storagemacro@@lastaddtocounter{#2}% + }% + }{% + \@@assoccnt@@standardaddtocounter{#2}{#1}% + \gdef\@@assoccnt@@storagemacro@@lastaddtocounter{#2}% + }% +}% + + +\newcommand{\@@assoccnt@@addtocounter}[2]{% + \ifcsdef{@@assoccnt@@suspendedcounterslist}{% + % Now, there are suspended counters -- do not update them! + \IsSuspendedCounter{#2}{% + % Nothing to be done + }{% + \@@assoccnt@@standardaddtocounter{#2}{#1}% + \gdef\@@assoccnt@@storagemacro@@lastaddtocounter{#2}% + }% + }{% + \@@assoccnt@@standardaddtocounter{#2}{#1}% + \gdef\@@assoccnt@@storagemacro@@lastaddtocounter{#2}% + }% +}% + + +\renewcommand{\addtocounter}[2]{% + \iftoggle{GlobalSuspend}{% + \IsSuspendedCounter{#1}{% + % No, do nothing at all% + }{% + \@@assoccnt@@standardaddtocounter{#1}{#2}% + \gdef\@@assoccnt@@storagemacro@@lastaddtocounter{#1}% + } + }{% + \@@assoccnt@@standardaddtocounter{#1}{#2}% + \gdef\@@assoccnt@@storagemacro@@lastaddtocounter{#1}% + }% + \ifcsdef{\@@assoccnt@@generatelistname{#1}}{% Check first, whether the list exists at all, + \forlistcsloop{\@@assoccnt@@addtocounter{#2}}{\@@assoccnt@@generatelistname{#1}}% March through the list + }{% + % No list -> do nothing at all + }% +}% + + + + +%%% addtocounter wrapper -- needs to switch the arguments for the command for the list usage!!! +\newcommand{\@@assoccnt@@setcounter}[3]{% + \IsAssociatedToCounter{#1}{#3}{% + \@@assoccnt@@standardsetcounter{#3}{#2}% + }{% + \GenericWarning{}{Warning: Counter "#3" is not part of the associated list counters to driver counter "#1"}% + }% +}% + + + + + + +\newcommand{\@@assoccnt@@stepcounter}[1]{% + \@@assoccnt@@standardstepcounter{#1}% + \gdef\@@assoccnt@@storagemacro@@laststeppedcounter{#1}% +}% + + +\newcommand{\@@assoccnt@@stepdrivencounters}[1]{% + \ifcsdef{\@@assoccnt@@generatelistname{#1}}{% Check first, whether the list exists at all, + \forlistcsloop{\@@assoccnt@@standardrefstepcounter}{\@@assoccnt@@generatelistname{#1}}% March through the list + }{% + }% +}% + + + +\renewcommand{\stepcounter}[1]{% + \@@assoccnt@@stepcounter{#1}% +}% + +%%% Wrapper --> use standard ref stepping to prevent labelling system going mental +\newcommand{\@@assocccnt@@refstepcounter}[1]{% % + \@@assoccnt@@standardrefstepcounter{#1}% +}% + +\renewcommand{\refstepcounter}[1]{% + \@@assoccnt@@refstepcounter{#1}% +}% + + +\newcommand{\@@assoccnt@@refstepcounter}[1]{% % + \gdef\@@assoccnt@@storagemacro@@lastrefsteppedcounter{#1}% + \if@calcpackage + \@@assoccnt@@stepdrivencounters{#1}% + \fi + \@@assoccnt@@standardrefstepcounter{#1}% +}% + +\renewcommand{\refstepcounter}[1]{% + \@@assoccnt@@refstepcounter{#1}% +}% + + + + +\listgadd{\@@assoccnt@@tempcounterlist}{}% This should be renamed later one... treated more generally + +\newcommand{\@@assoccnt@@setcounterwrapper}[3]{% + \ifcsdef{\@@assoccnt@@generatelistname{#1}}{% Check first, whether the per driver list exists at all, + \forlistcsloop{\@@assoccnt@@setcounter{#1}{#2}}{#3}% + }{}% +}% + + +\define@boolkey{\@@assoccnt@@keys}{AssociatedToo}[false]{% +}% + +\define@key{\@@assoccnt@@keys}{AssociatedCounters}{% + \undef{\@@assoccnt@@tempcounterlist}% + \def\@@assoccnt@@keymacro@@associatedcounters{#1}% + \forcsvlist{\listgadd{\@@assoccnt@@tempcounterlist}}{#1}% +}% + + +%% Redefined \setcounter -- with additional optional key% + +\renewcommand{\setcounter}[3][]{% + \@@assoccnt@@standardsetcounter{#2}{#3}% + \gdef\@@assoccnt@@storagemacro@@lastsetcounter{#2}% + \setkeys{\@@assoccnt@@keys}{AssociatedToo=false,#1}% + \ifKV@assoccntkeyfamily@AssociatedToo + \@@assoccnt@@setcounterwrapper{#2}{#3}{\@@assoccnt@@generatelistname{#2}}% + \else% + \ifdef{\@@assoccnt@@keymacro@@associatedcounters}{% + \@@assoccnt@@setcounterwrapper{#2}{#3}{@@assoccnt@@tempcounterlist}% + \undef{\@@assoccnt@@tempcounterlist}% Clear the counter list + \listgadd{\@@assoccnt@@tempcounterlist}{}% Redefine the list for future use% + \undef{\@@assoccnt@@keymacro@@associatedcounters}% + }{}% + \fi% +}% + + + +\newcommand{\LastSteppedCounter}{% + \ifdef{% + \@@assoccnt@@storagemacro@@laststeppedcounter% + }{% + \@@assoccnt@@storagemacro@@laststeppedcounter% + }{% + Undefined/unknown% + }% +}% + +\newcommand{\LastSetCounter}{% + \@@assoccnt@@storagemacro@@lastsetcounter% +}% + +\newcommand{\LastRefSteppedCounter}{% + \@@assoccnt@@storagemacro@@lastrefsteppedcounter% +}% + +\newcommand{\LastAddedToCounter}{% + \@@assoccnt@@storagemacro@@lastaddtocounter% +}% + + + +\endinput%
\ No newline at end of file |