From 62343452c8e0aff0f46aa81463462fa3fa98f579 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Sat, 7 Nov 2015 23:20:16 +0000 Subject: xassoccnt (7nov15) git-svn-id: svn://tug.org/texlive/trunk@38795 c570f23f-e606-0410-a88d-b1316a301751 --- .../texmf-dist/tex/latex/xassoccnt/xassoccnt.sty | 835 +++++++++++++++++++++ 1 file changed, 835 insertions(+) create mode 100644 Master/texmf-dist/tex/latex/xassoccnt/xassoccnt.sty (limited to 'Master/texmf-dist/tex/latex') diff --git a/Master/texmf-dist/tex/latex/xassoccnt/xassoccnt.sty b/Master/texmf-dist/tex/latex/xassoccnt/xassoccnt.sty new file mode 100644 index 00000000000..af5d532a123 --- /dev/null +++ b/Master/texmf-dist/tex/latex/xassoccnt/xassoccnt.sty @@ -0,0 +1,835 @@ +\def\xassoccntpackageversion{0.1} +\NeedsTeXFormat{LaTeX2e} + +\ProvidesPackage{xassoccnt}[2015/11/07 - v\xassoccntpackageversion] + +\RequirePackage{xcolor} +\RequirePackage{xparse} +\RequirePackage{l3keys2e} + +\ExplSyntaxOn + +% First some local or global values + +\int_new:N \l__xassoccnt_initialcountervalue_int +\int_new:N \g__xassoccnt_lastcountervalue_int + +\bool_new:N \g__xassoccnt_autodefine_counters % --> global document option + +\clist_new:N \l__xassoccnt_exclude_clist % clist for +\clist_new:N \l__xassoccnt_onlycounters_clist % clist for the \SetDocumentCounter command + +\bool_new:N \l__xassoccnt_autodefine_none +\bool_new:N \l__xassoccnt_autodefine_drivercounter +\bool_new:N \l__xassoccnt_autodefine_allcounters +\bool_new:N \l__xassoccnt_autodefine_associatedcounter + +\bool_new:N \l__xassoccnt_countertype_general +\bool_new:N \l__xassoccnt_countertype_driver +\bool_new:N \l__xassoccnt_countertype_associated + + + +\cs_new:Nn \__xassoccnt_toggle_bool:n {% + \bool_if:nTF{#1}{\bool_set_false:n {#1}}{\bool_set_false:n {#1}} +} + +\cs_generate_variant:Nn \__xassoccnt_toggle_bool:n { c } + + +\cs_new:Nn \__xassoccnt_toggle_autodefine:n {% + \clist_set:Nn \l_tmpa_clist {#1} + \clist_map_inline:Nn \l_tmpa_clist {\__xassoccnt_toggle_bool:c {l__xassoccnt_autodefine_##1} } +} + +\cs_new:Nn \__xassoccnt_set_false:n {% + \clist_set:Nn \l_tmpa_clist {#1} + \clist_map_inline:Nn \l_tmpa_clist {\bool_set_false:c {##1} } +} + +\cs_new:Nn \__xassoccnt_set_true:n {% + \clist_set:Nn \l_tmpa_clist {#1} + \clist_map_inline:Nn \l_tmpa_clist {\bool_set_true:c {##1} } +} + + + +\keys_define:nn {xassoccnt} +{ + initial .code:n={ \int_set:Nn \l__xassoccnt_initialcountervalue_int {#1}}, + sloppy .bool_set:N=\l__xassoccnt_sloppy_newcounter, + autodefinecounters .bool_set:N=\g__xassoccnt_autodefine_counters, + % Choice keys + autodefine .choice:, + autodefine / all .code:n= {\bool_set_true:N \l__xassoccnt_autodefine_allcounters + \__xassoccnt_set_true:n {l__xassoccnt_autodefine_drivercounter, + l__xassoccnt_autodefine_associateddrivercounter } + \bool_set_false:N \l__xassoccnt_autodefine_none }, + autodefine / driver .code:n= {\bool_set_true:N \l__xassoccnt_autodefine_drivercounter}, + autodefine / associated .code:n= {\bool_set_true:N \l__xassoccnt_autodefine_associatedcounter + \__xassoccnt_set_false:n {l__xassoccnt_autodefine_allcounters,l__xassoccnt_autodefine_none}}, + autodefine / none .code:n= {\bool_set_true:N \l__xassoccnt_autodefine_none + \__xassoccnt_set_false:n {l__xassoccnt_autodefine_allcounters, + l__xassoccnt_autodefine_associatedcounter, + l__xassoccnt_autodefine_drivercounter}}, + autodefine .initial:n= {none}, % No autodefinition by default + + associatedtoo .code:n={ \clist_clear:N \l__xassoccnt_onlycounters_clist}, + associatedtoo .bool_set:N={\l__xassoccnt_setcounter_associated}, + associatedtoo .initial:n={false}, + onlycounters .code:n={\bool_set_false:N \l__xassoccnt_setcounter_associated + \clist_set:Nn \l__xassoccnt_onlycounters_clist {#1} }, + + exclude .clist_set:N=\l__xassoccnt_exclude_clist, + +%% For later purposes + countertype .choice:, + countertype / general .code:n= {\bool_set_true:N \l__xassoccnt_countertype_general }, + countertype / driver .code:n= {\bool_set_true:N \l__xassoccnt_countertype_driver }, + countertype / associated .code:n= {\bool_set_true:N \l__xassoccnt_countertype_associated }, + countertype .initial:n={ general } +} + +\ProcessKeysOptions{xassoccnt} + + +\msg_new:nnn{xassoccnt}{counteralreadyexists}{% + Error:~Counter~#1~already~exists\\ +} + + +\msg_new:nnn{xassoccnt}{crossassociation}{% + Error:~You~can't~cross-associate~two~counters\\ + Here:~The~counters~#1~and~#2~should~not~be~associated~to~each~other~since~one~is~already~associated~to~the~other~one% +} + +\msg_new:nnn{xassoccnt}{selfassociation}{% + Warning:~An~accidental(?)~self-association~of~counter~"#1"~was~detected\\ + This~will~be~ignored! +} + + +\msg_new:nnn{xassoccnt}{addwithoutdeclaration}{% + Warning:~An~accidental(?)~addition~of~associated~counter(s)~without~DeclareAssociatedCounters~was~detected~for\\ + the~driver~counter~"#1"~and~following~driven~counters:\\ + ---~#2~--- +} + +\cs_new:Nn \__xassoccnt_stpelt:n{\global\csname c@#1\endcsname \c_minus_one\xassoccnt_addtocounter{#1}{\c_one}}% + + +\cs_new:Nn \__xassoccnt_intinc:n {\int_gincr:N \l_xassoccnt_resetlist_counter}% + +\int_new:N \l_xassoccnt_resetlist_counter + +\cs_new:Nn \xassoccnt_countersinresetlist:n {% + \begingroup + \int_zero:N \l_xassoccnt_resetlist_counter + \cs_set_eq:NN \@elt \__xassoccnt_intinc:n +% \def\@elt##1{\int_gincr:N \l_xassoccnt_resetlist_counter}% Increase the 'counter' globally + \use:c{ cl@#1 } + \endgroup +} + + + +\cs_set_eq:NN \xassoccnt_standardstepcounter \stepcounter +\cs_set_eq:NN \xassoccnt_standardrefstepcounter \refstepcounter +\cs_set_eq:NN \xassoccnt_standardaddtocounter \addtocounter +\cs_set_eq:NN \xassoccnt_standardsetcounter \setcounter + +\cs_new_nopar:Nn \__xassoccnt_laststeppedcounter: {} +\cs_new_nopar:Nn \__xassoccnt_lastrefsteppedcounter: {} +\cs_new_nopar:Nn \__xassoccnt_lastaddtocounter: {} +\cs_new_nopar:Nn \__xassoccnt_lastsetcounter: {} +\cs_new_nopar:Nn \__xassoccnt_lastsetdocumentcounter: {} + + +\cs_new:Nn \xassoccnt_counter_container:n {% + \seq_new:c{\__xassoccnt_generate_countercontainername:n{#1}}% + \cs_new_nopar:cn {__xassoccnt_#1container:} {\__xassoccnt_generate_countercontainername:n{#1}}% +} + +\cs_new:Nn \__xassoccnt_generate_countercontainername:n {% + g_xassoccnt_#1cnt_seq% +} + +\str_const:Nn \c_xassoccnt_undefined_str {undefined} +\str_const:Nn \c_xassoccnt_mastername_str {master} +\str_const:Nn \c_xassoccnt_associatedname_str {associated} +\str_const:Nn \c_xassoccnt_suspendedname_str {suspended} + +\clist_new:N \__g_xassoccnt_countercontainer_clist +\clist_set:Nn \__g_xassoccnt_countercontainer_clist {% + \c_xassoccnt_undefined_str, + \c_xassoccnt_mastername_str, + \c_xassoccnt_associatedname_str, + \c_xassoccnt_suspendedname_str +} + +% Now generate the containers and the accessing functions +\clist_map_function:NN \__g_xassoccnt_countercontainer_clist \xassoccnt_counter_container:n + +\cs_new:Nn \__xassoccnt_drivercontainer:n {g_xassoccnt_#1cnt_seq} + +\cs_new:Nn \__xassoccnt_containerremoveduplicates:N { \seq_gremove_duplicates:N #1 } + +\cs_generate_variant:Nn \__xassoccnt_containerremoveduplicates:N { c } + +\cs_new_nopar:Nn \__xassoccnt_container_removeduplicates:n { \seq_gremove_duplicates:c{\__xassoccnt_generate_countercontainername:n{#1}}} +\cs_new_nopar:Nn \__xassoccnt_container_removecounter:nn { \seq_gremove_all:cn{\__xassoccnt_generate_countercontainername:n{#1}}{#2} } +\cs_new_nopar:Nn \__xassoccnt_container_putright:nn { \seq_put_right:cn{\__xassoccnt_generate_countercontainername:n{#1}}{#2} } +\cs_new_nopar:Nn \__xassoccnt_container_removeassociated:nn { \seq_gremove_all:cn{\__xassoccnt_drivercontainer:n{#1}}{#2}} +\cs_new_nopar:Nn \__xassoccnt_container_gclear:n {\seq_gclear:N #1 } +\cs_new_nopar:Nn \__xassoccnt_container_clear:n {\seq_clear:N #1 } + + + +\cs_new_nopar:Nn \__xassoccnt_container_perdriver_new:n { + \seq_if_exist:cF{ \__xassoccnt_drivercontainer:n {#1} } + { % Generate only if there is no driver container sequence so far! + \seq_new:c{\__xassoccnt_drivercontainer:n{#1} } + } +} + + +\cs_generate_variant:Nn \__xassoccnt_container_gclear:n { c } +\cs_generate_variant:Nn \__xassoccnt_container_clear:n { c } + +\cs_new:Nn \__xassoccnt_container_set_from_clist:NN {\seq_set_from_clist:NN #1 #2} +\cs_generate_variant:Nn \__xassoccnt_container_set_from_clist:NN { cN, cc, Nc } + +\cs_new:Nn \__xassoccnt_gcombine_container:NN {% + \seq_concat:NNN \l_tmpb_seq #1 #2 + \seq_gset_eq:NN #1 \l_tmpb_seq +} + +\cs_generate_variant:Nn \__xassoccnt_gcombine_container:NN { cc } + +\cs_new:Nn \__xassoccnt_gcombineunique_container:NN {% + \__xassoccnt_gcombine_container:NN #1 #2 + \__xassoccnt_containerremoveduplicates:N #1 +} + +\cs_generate_variant:Nn \__xassoccnt_gcombineunique_container:NN { cc } + +\cs_new:Nn \__xassoccnt_adddrivercounter:nn{ % + \__xassoccnt_setupcontainers:n{#2}% +} + + +\cs_new:Nn \__xassoccnt_removedrivercounter:nn{% + \__xassoccnt_container_gclear:c{\__xassoccnt_drivercontainer:n{#2}} % Clear the per-counter container first + \__xassoccnt_container_removecounter:nn{\c_xassoccnt_mastername_str}{#2} % Remove the counter #2 from the master container + \cs_undefine:c{\__xassoccnt_drivercontainer:n{#2}} +} + +\cs_new:Nn \__xassoccnt_autodefine_associatedcounters:nn {% + \bool_if:nTF{ \g__xassoccnt_autodefine_counters }{% + \seq_map_inline:Nn #2 { \__xassoccnt_newcounter_ltx:nnn {sloppy}{##1}{} } + }{% + \keys_set:nn{xassoccnt}{#1} + \bool_if:nF{ \l__xassoccnt_autodefine_none }{% + % No, some autodefine key has been specified + \bool_if:nTF { \l__xassoccnt_autodefine_allcounters } + {% + \seq_map_inline:Nn #2 { \__xassoccnt_newcounter_ltx:nnn {sloppy}{##1}{} } %loop through the list and do not complain if the counter ##1 already exists + }{% + \bool_if:nT { \l__xassoccnt_autodefine_associatedcounter }{% + \seq_map_inline:Nn #2 { \__xassoccnt_newcounter_ltx:nnn {sloppy}{##1}{}} + } + } + } + } +} + +\cs_new:Nn \__xassoccnt_autodefine_drivercounter:nn {% + \keys_set:nn{ xassoccnt } {#1} + \bool_if:nTF{ \g__xassoccnt_autodefine_counters }{% + \__xassoccnt_newcounter_ltx:nnn{#1,sloppy}{#2}{}% + }{% + \bool_if:nT {\l__xassoccnt_autodefine_drivercounter || \l__xassoccnt_autodefine_allcounters } {% + \__xassoccnt_newcounter_ltx:nnn{#1}{#2}{} + } + } +} + + + + +\cs_new:Nn \__xassoccnt_addassociatedcounters:nnn {% + \keys_set:nn{xassoccnt}{#1} + \clist_set:Nx \l_tmpa_clist {#3}% + \clist_if_in:NnT \l_tmpa_clist{#2}{% Prevent self-association + \msg_warning:nnn{xassoccnt}{selfassociation}{#2}% Warning + \clist_gremove_all:Nn \l_tmpa_clist {#2}% + }% + \clist_remove_duplicates:N \l_tmpa_clist% + \__xassoccnt_container_set_from_clist:NN \l_tmpa_seq \l_tmpa_clist + \seq_if_in:cnF{\__xassoccnt_mastercontainer:}{#2}{% + \__xassoccnt_adddrivercounter:nn{#1}{#2}% Generate the driver counter container + \msg_warning:nnnn{xassoccnt}{addwithoutdeclaration}{#2}{#3} % Warning --> associated some counter without declaring in the preamble + }% + \__xassoccnt_gcombineunique_container:cc{\__xassoccnt_drivercontainer:n{#2}}{l_tmpa_seq} + \__xassoccnt_gcombineunique_container:cc{\__xassoccnt_generate_countercontainername:n{\c_xassoccnt_associatedname_str}}{l_tmpa_seq} + % Do only define if really needed + \__xassoccnt_autodefine_associatedcounters:nn {#1} {\l_tmpa_seq } +} + + +\cs_new:Nn \xassoccnt_removesuspendedcounters:nn{% + \seq_if_exist:cTF{\__xassoccnt_suspendedcontainer:}{% + \seq_if_in:cnT{\__xassoccnt_suspendedcontainer:}{#2}{% + \__xassoccnt_container_removecounters:nn{suspended}{#2} + }% + }% +} + + +\cs_new:Nn \__xassoccnt_setupcontainers:n{% + \__xassoccnt_container_putright:nn{master}{#1} + \__xassoccnt_container_removeduplicates:n{master}% + \__xassoccnt_container_perdriver_new:n{#1}% +} + + +\cs_new:Nn \__xassoccnt_newcounter_ltx:nn{% + \keys_set:nn {xassoccnt}{sloppy=false,initial=\c_zero,#1} + \cs_if_exist:cTF{c@#2}{% + \bool_if:nF {\l__xassoccnt_sloppy_newcounter }{ + \msg_error:nnn{xassoccnt}{counteralreadyexists}{#2}% Warning + } + }{% + \newcounter{#2}% + \xassoccnt_standardsetcounter{#2}{\l__xassoccnt_initialcountervalue_int} + }% +} + +\cs_new:Nn \__xassoccnt_newcounter_ltx:nnn{% + \keys_set:nn {xassoccnt}{sloppy=false,initial=\c_zero,#1} + \str_set:Nx \l_tmpa_str {#3} + \__xassoccnt_latexcounter_exists:nTF{#2}{% + \bool_if:nF {\l__xassoccnt_sloppy_newcounter }{ + \msg_error:nnn{xassoccnt}{counteralreadyexists}{#2}% Warning + } + }{% + \str_if_empty:NTF \l_tmpa_str {% + \newcounter{#2}% + }{% + \newcounter{#2}[#3]% + }% + \xassoccnt_standardsetcounter{#2}{\l__xassoccnt_initialcountervalue_int} + } +} + + + + +\cs_new:Nn \xassoccnt_declareassociatedcounters:nnn {% + \__xassoccnt_container_if_in:cnTF{\__xassoccnt_generate_countercontainername:n{\c_xassoccnt_mastername_str}:}{#2}{% + % Not contained in the driver counter list + \__xassoccnt_addassociatedcounters:nnn{#1}{#2}{#3}% + }{% + % Check first if there is a potential cross association + \__xassoccnt_adddrivercounter:nn{#1}{#2}% + \xassoccnt_is_associatedtocounter:nnTF{#3}{#2}{% + \msg_fatal:nnnn{xassoccnt}{crossassociation}{#2}{#3}% Fatal message + % Not necessary unless the fatal message above is removed + \__xassoccnt_container_removecounter:cn{\__xassoccnt_generate_countercontainername:n{\c_xassoccnt_mastername_str}:}{#2} + }{% No, we don't try to cross-associate two counters + \__xassoccnt_addassociatedcounters:nnn{#1}{#2}{#3}% + }% + }% + \__xassoccnt_container_removeduplicates:n{\__xassoccnt_drivercontainer:n{#2}} + \__xassoccnt_autodefine_drivercounter:nn { }{#2} +} + + + + + +\prg_new_conditional:Nnn \xassoccnt_is_drivercounter:n {T,F,TF} +{ + \seq_if_in:cnTF{\__xassoccnt_mastercontainer:}{#1}{% + \prg_return_true: + }{ + \prg_return_false: + } +} + + +\prg_new_conditional:Nnn \__xassoccnt_container_if_in:Nn { T, F, TF } +{ + \seq_if_in:NnTF #1 {#2}{% + \prg_return_true: + }{ + \prg_return_false: + } +} + +\cs_generate_variant:Nn \__xassoccnt_container_if_in:NnTF { cnTF } +\cs_generate_variant:Nn \__xassoccnt_container_if_in:NnT { cnT } +\cs_generate_variant:Nn \__xassoccnt_container_if_in:NnF { cnF } + +\prg_new_conditional:Nnn \xassoccnt_is_associatedcounter:n {T,F,TF} +{ + \__xassoccnt_container_if_in:cnTF{\__xassoccnt_generate_countercontainername:n{\c_xassoccnt_associatedname_str}}{#1}{% + \prg_return_true: + }{ + \prg_return_false: + } +} + +\prg_new_conditional:Nnn \xassoccnt_is_suspendedcounter:n {TF,T,F} +{% + \__xassoccnt_container_if_in:cnTF{\__xassoccnt_generate_countercontainername:n{\c_xassoccnt_suspendedname_str}}{#1}{% + \prg_return_true: + }{% + \prg_return_false: + }% +} + + + +\prg_new_conditional:Nnn \xassoccnt_is_associatedtocounter:nn {T,F,TF} +{ + \xassoccnt_is_drivercounter:nTF{#1}{% + \seq_if_in:cnTF{\__xassoccnt_drivercontainer:n{#1}}{#2}{% + \prg_return_true: + }{% + \prg_return_false: + }% + }{% + \prg_return_false: + }% +} + +%% Clearing functions + +\cs_new:Nn \xassoccnt_remove_associatedcounter:nnn +{ + \__xassoccnt_container_removeassociated:nn{#2}{#3} + \__xassoccnt_container_removecounter:nn{\c_xassoccnt_associatedname_str}{#3}% +} + +\cs_new:Nn \xassoccnt_remove_associatedcounters:nnn +{% + \clist_set:Nx \l_tmpa_clist {#3} + \seq_set_from_clist:NN \l_tmpa_seq \l_tmpa_clist + \seq_map_inline:Nn \l_tmpa_seq { \xassoccnt_remove_associatedcounter:nnn{#1}{#2}{##1} } % Remove one counter after another one! +} + + +\cs_new:Nn \xassoccnt_gclear_associatedcounters:nn {% + \seq_map_inline:cn {\__xassoccnt_drivercontainer:n{#2}} { \__xassoccnt_container_removecounter:nn{\c_xassoccnt_associatedname_str}{##1} }% Remove from associated list container + \__xassoccnt_container_gclear:c {\__xassoccnt_drivercontainer:n{#2} } +} +%%%%%%%%%%%%%%%%%%%%% User interface routines + + +\NewDocumentCommand{\SuspendCounters}{O{}m}{% + \keys_set:nn { xassoccnt }{#1}% +% \clist_if_empty:NF \l__xassoccnt_onlycounters_clist {% + \__xassoccnt_container_putright:nn{\c_xassoccnt_suspendedname_str}{#2} +} + + +\NewDocumentCommand{\ResumeSuspendedCounters}{O{}m}{% + \__xassoccnt_container_removecounter:nn{\c_xassoccnt_suspendedname_str}{#2} +} + + +\NewDocumentCommand{\DeclareAssociatedCounters}{omm}{% + \IfValueTF{#1}{% + \keys_set:nn {xassoccnt} {#1} + \xassoccnt_declareassociatedcounters:nnn{#1}{#2}{#3}% + }{% + % Disable the automated definition of counters explicitly + \xassoccnt_declareassociatedcounters:nnn{autodefine=none}{#2}{#3}% + } +} + + +\NewDocumentCommand{\AddDriverCounter}{O{}m}{% + \xassoccnt_adddrivercounter:nn{#1}{#2} +} + +\NewDocumentCommand{\AddAssociatedCounters}{O{}mm}{% + %Check first if we are in document or in preamble: + \ifx\@onlypreamble\@notprerr + % Explicitly disable autodefinition of counters + \__xassoccnt_addassociatedcounters:nnn{#1,autodefine=none}{#2}{#3}% + \else + % No, it's the preamble, fall back to `\DeclareAssociatedCounters + \DeclareAssociatedCounters[#1]{#2}{#3} + \fi +} + +\NewDocumentCommand{\RemoveDriverCounter}{O{}m}{% + \__xassoccnt_removedrivercounter:nn{#1}{#2}% +} + +\NewDocumentCommand{\GetDriverCounter}{O{,}m}{% + \seq_clear:N \l_tmpa_seq + \seq_map_inline:cn {\__xassoccnt_mastercontainer:}{% + \seq_if_in:cnT{\__xassoccnt_drivercontainer:n{##1}}{#2}{% + \seq_put_right:Nn \l_tmpa_seq{##1} + }% + }% + \seq_if_empty:NTF \l_tmpa_seq{--}{\seq_use:Nn \l_tmpa_seq {#1}} +} + + + +\prg_new_conditional:Nnn \__xassoccnt_ifis_latexcounter:n {T,F,TF} +{% + \cs_if_exist:cTF {c@#1}{% + \prg_return_true: + }{% + \prg_return_false: + }% +} + +\prg_new_conditional:Nnn \__xassoccnt_latexcounter_exists:n {T,F,TF} +{% + \cs_if_exist:cTF {c@#1}{% + \prg_return_true: + }{% + \prg_return_false: + }% +} + + +\NewDocumentCommand{\IfIsDocumentCounterTF}{om+m+m}{% + \__xassoccnt_ifis_latexcounter:nTF {#2}{ #3 } { #4 } +} + +\NewDocumentCommand{\IfIsDocumentCounterT}{om+m}{% + \__xassoccnt_ifis_latexcounter:nT {#2}{ #3 } +} + + +\NewDocumentCommand{\IfIsDocumentCounterF}{om+m}{% + \__xassoccnt_ifis_latexcounter:nF {#2}{ #3 } +} + + +\NewDocumentCommand{\IsDriverCounter}{O{}mmm}{% + \xassoccnt_is_drivercounter:nTF{#2}{#3}{#4}% +} + +\NewDocumentCommand{\IsAssociatedToCounter}{O{}mmmm}{% + \xassoccnt_is_associatedtocounter:nnTF{#2}{#3}{% + #4% + }{% + #5% + }% +} + +\NewDocumentCommand{\IsAssociatedCounter}{O{}mmm}{% + \xassoccnt_is_associatedcounter:nTF{#2}{#3}{#4}% +} + + +\NewDocumentCommand{\IsSuspendedCounter}{O{}mmm}{% + \xassoccnt_is_suspendedcounter:nTF{#2}{#3}{#4}% +} + + + +\NewDocumentCommand{\IfExistsDriverCounterList}{mmm}{% + \seq_if_exist:cTF{\__xassoccnt_drivercontainer:n{#1}}{% + #2% + }{% + #3% + }% +} + +\NewDocumentCommand{\RemoveAssociatedCounters}{O{}mm}{% + \xassoccnt_remove_associatedcounters:nnn{#1}{#2}{#3} +} + +\NewDocumentCommand{\RemoveAssociatedCounter}{O{}mm}{% + \xassoccnt_remove_associatedcounter:nnn{#1}{#2}{#3} +} + +\NewDocumentCommand{\ClearAssociatedCounters}{O{}m}{% + \xassoccnt_gclear_associatedcounters:nn{#1}{#2}% +} + + + +\NewDocumentCommand{\ShowAssociatedCountersList}{m}{% + {\color{red}% + \fbox{#1}~has~\seq_use:cn {\__xassoccnt_drivercontainer:n{#1}}{\par\noindent} + } +} + +\NewDocumentCommand{\ShowAllAssociatedCounters}{}{% + {\color{brown}% + \seq_use:cn {\__xassoccnt_associatedcontainer:}{\par\noindent} + } +} + + +\NewDocumentCommand{\ShowDriverCounterList}{}{% + {\color{blue}% + \seq_use:cn{\__xassoccnt_mastercontainer:}{\par\bigskip\noindent} + }% +} + + + +\RenewDocumentCommand{\stepcounter}{m}{% + \xassoccnt_is_suspendedcounter:nF{#1}{% + \cs_gset_nopar:Nn \__xassoccnt_laststeppedcounter: {#1}% + \xassoccnt_countersinresetlist:n{#1}% + \int_compare:nTF{% + \l_xassoccnt_resetlist_counter > \c_zero + }{% + \xassoccnt_standardaddtocounter{#1}{\c_one}% + \begingroup + \cs_set_eq:NN \@elt \__xassoccnt_stpelt:n + \use:c{cl@#1} + \endgroup + }{% + \xassoccnt_standardaddtocounter{#1}{\c_one} + } + \int_gset:Nn \g__xassoccnt_lastcountervalue_int {\number\value{#1}}% + \seq_if_exist:cT { \__xassoccnt_drivercontainer:n{#1} } + { \seq_map_inline:cn {\__xassoccnt_drivercontainer:n{#1} } + { \xassoccnt_addtocounter{##1}{\c_one} } + }% End of \seq_if_exist + }% +} + + + +\NewDocumentCommand{\xassoccnt_addtocounter}{mmO{}}{% + % Only add to a counter if this counter isn't on the suspended counters list! + \xassoccnt_is_suspendedcounter:nF{#1}{% + \xassoccnt_standardaddtocounter{#1}{#2}% + \cs_gset_nopar:Nn \__xassoccnt_lastaddtocounter: {#1}% + }% +} + + +\cs_new:Nn \__xassoccnt_setdocumentcounter:nnn { + \xassoccnt_standardsetcounter{#2}{#3}% + \clist_clear:N \l__xassoccnt_onlycounters_clist + \keys_set:nn {xassoccnt}{#1}% + \bool_if:nTF {\l__xassoccnt_setcounter_associated } {% + \seq_if_exist:cT { \__xassoccnt_drivercontainer:n{#2} } + { \seq_map_inline:cn {\__xassoccnt_drivercontainer:n{#2} } + { \xassoccnt_standardsetcounter{##1}{#3} } + }% End of \seq_if_exist + }{% + % Check whether the `onlycounters` - clist is empty -- if not, loop through the list + \clist_if_empty:NF \l__xassoccnt_onlycounters_clist {% + \seq_if_exist:cT { \__xassoccnt_drivercontainer:n{#2} } + { + \clist_map_inline:Nn \l__xassoccnt_onlycounters_clist + { % Check first if ##1 is associated to #2 at all + \xassoccnt_is_associatedtocounter:nnT {#2} {##1} { \xassoccnt_standardsetcounter{##1}{#3} } + } + } + } + } + \cs_gset_nopar:Nn \__xassoccnt_lastsetdocumentcounter: {#2}% + \int_gset:Nn \g__xassoccnt_lastcountervalue_int {\number\value{#2}}% +} + + +\cs_new:Nn \__xassoccnt_synccounters:nn {% + \int_set:Nn \l_tmpa_int {\value{#2}} + \__xassoccnt_setdocumentcounter:nnn {associatedtoo=true,#1}{#2}{\l_tmpa_int} % copy the driver counter value to all associated counters + \int_zero:N \l_tmpa_int +} + +\cs_new:Nn \__xassoccnt_copycounters:nnn {% + \xassoccnt_standardsetcounter{#3}{\value{#2}} +} + + +\cs_new:Nn \__xassoccnt_swapcounters:nnn {% + \int_set:Nn \l_tmpa_int {\value{#2}}% + \xassoccnt_standardsetcounter{#2}{\value{#3}} + \xassoccnt_standardsetcounter{#3}{\l_tmpa_int} + \int_zero:N \l_tmpa_int +} + + + + + +% Extended support layer for counters +\NewDocumentCommand{\SetDocumentCounterOld}{O{associatedtoo=false}mm}{% + \xassoccnt_standardsetcounter{#2}{#3}% + \clist_clear:N \l__xassoccnt_onlycounters_clist + \keys_set:nn {xassoccnt}{#1}% + \bool_if:nTF {\l__xassoccnt_setcounter_associated } {% + \seq_if_exist:cT { \__xassoccnt_drivercontainer:n{#2} } + { \seq_map_inline:cn {\__xassoccnt_drivercontainer:n{#2} } + { \xassoccnt_standardsetcounter{##1}{#3} } + }% End of \seq_if_exist + }{% + % Check whether the `onlycounters` - clist is empty -- if not, loop through the list + \clist_if_empty:NF \l__xassoccnt_onlycounters_clist {% + \seq_if_exist:cT { \__xassoccnt_drivercontainer:n{#2} } + { + \clist_map_inline:Nn \l__xassoccnt_onlycounters_clist + { % Check first if ##1 is associated to #2 at all + \xassoccnt_is_associatedtocounter:nnT {#2} {##1} { \xassoccnt_standardsetcounter{##1}{#3} } + } + } + } + } + \cs_gset_nopar:Nn \__xassoccnt_lastsetdocumentcounter: {#2}% + \int_gset:Nn \g__xassoccnt_lastcountervalue_int {\number\value{#2}}% +} + + +\NewDocumentCommand{\SetDocumentCounter}{O{associatedtoo=false}mm}{% + \__xassoccnt_setdocumentcounter:nnn {#1}{#2}{#3} % copy the driver counter value to all associated counters +} + +\NewDocumentCommand{\SyncCounters}{om}{% + \IfValueTF{#1}{% + \__xassoccnt_synccounters:nn {#1}{#2} + }{% + \__xassoccnt_synccounters:nn {}{#2} + } +} + + +\RenewDocumentCommand{\setcounter}{mm}{% + \cs_gset_nopar:Nn \__xassoccnt_lastsetcounter: {#1} + \xassoccnt_standardsetcounter{#1}{#2}% + \int_gset:Nn \g__xassoccnt_lastcountervalue_int {\number\value{#1}}% +} + + +\RenewDocumentCommand{\refstepcounter}{m}{% + \cs_gset_nopar:Nn \__xassoccnt_lastrefsteppedcounter: {#1} + \xassoccnt_standardrefstepcounter{#1}% + \int_gset:Nn \g__xassoccnt_lastcountervalue_int {\number\value{#1}}% +} + +%%%% Now some wrapper macros for information on the last counter changed + +\newcommand{\LastSteppedCounter}{% + \__xassoccnt_laststeppedcounter: +} + + +\newcommand{\LastRefSteppedCounter}{% + \__xassoccnt_lastrefsteppedcounter: +} + +\newcommand{\LastAddedToCounter}{% + \__xassoccnt_lastaddtocounter: +} + +\newcommand{\LastSetCounter}{% + \__xassoccnt_lastsetcounter: +} + +\newcommand{\LastSetDocumentCounter}{% + \__xassoccnt_lastsetdocumentcounter: +} + + +%%%%%%%%% + + +\newcommand{\LastCounterValue}{% +%\NewDocumentCommand{\LastCounterValue}{}{% + \int_use:N \g__xassoccnt_lastcountervalue_int +} + + + +\NewDocumentCommand{\NewDocumentCounter}{O{initial=\c_zero}mo}{% + \IfValueTF{#3}{% + \__xassoccnt_newcounter_ltx:nnn{#1}{#2}{#3} + }{% + \__xassoccnt_newcounter_ltx:nnn{#1}{#2}{} + } +} + + + +\NewDocumentCommand{\CopyDocumentCounters}{O{}mm}{% + \__xassoccnt_copycounters:nnn{#1}{#2}{#3}% +} + +\NewDocumentCommand{\SwapDocumentCounters}{O{}mm}{% + \__xassoccnt_swapcounters:nnn{#1}{#2}{#3}% +} + + +\newcommand{\countersresetlistcount}[1]{% + \int_zero:N \l_xassoccnt_resetlist_counter% + \xassoccnt_countersinresetlist:n{#1}% +} + +\newcommand{\getresetlistcount}{% + \int_use:N \l_xassoccnt_resetlist_counter +} + +\bool_new:N \l__xassoccnt_isinresetlist_bool + + +\prg_new_conditional:Nnn \__xassoccnt_ifinresetlist:nn {T,F,TF} +{% + \bool_set_false:N \l__xassoccnt_isinresetlist_bool + \cs_set:Nn \l__tmpa_cs: {#2} + \def\@elt##1{% Can't use \cs_new:Nn here :-( + \cs_set:Nn \l__tmpb_cs: {##1} + % Check if \l__tmpa_cs: and \l__tmpb_cs: are equal + \cs_if_eq:NNT \l__tmpa_cs: \l__tmpb_cs: { + \bool_set_true:N \l__xassoccnt_isinresetlist_bool + } + } + \use:c{ cl@#1 } + \bool_if:nTF {\l__xassoccnt_isinresetlist_bool}{% + \prg_return_true: + }{% + \prg_return_false: + } +} + +\NewDocumentCommand{\IfInResetListTF}{omm+m+m}{% + \bool_set_true:N \l__xassoccnt_isinresetlist_bool + \__xassoccnt_ifinresetlist:nnTF{#2}{#3}{#4}{#5}% +} + +\NewDocumentCommand{\IfInResetListT}{omm+m}{% + \__xassoccnt_ifinresetlist:nnT{#2}{#3}{#4}% +} + +\NewDocumentCommand{\IfInResetListF}{omm+m}{% + \__xassoccnt_ifinresetlist:nnF{#2}{#3}{#4}% +} + + +\ExplSyntaxOff + + +%%%%%%%%%%% + +% Extended interface functions + + +\NewDocumentCommand{\DeclareDocumentCounter}{O{initial={0}}mo}{% + \IfValueTF{#3}{% + \NewDocumentCounter[#1]{#2}[#3]% + }{% + \NewDocumentCounter[#1]{#2}% + }% +} + +\@onlypreamble{\DeclareAssociatedCounters} +\@onlypreamble{\DeclareDocumentCounter} + +\endinput \ No newline at end of file -- cgit v1.2.3