%%%============================================================================== %% Copyright 2023-present by Alceu Frigeri %% %% This work may be distributed and/or modified under the conditions of %% %% * The [LaTeX Project Public License](http://www.latex-project.org/lppl.txt), %% version 1.3c (or later), and/or %% * The [GNU Affero General Public License](https://www.gnu.org/licenses/agpl-3.0.html), %% version 3 (or later) %% %% This work has the LPPL maintenance status *maintained*. %% %% The Current Maintainer of this work is Alceu Frigeri %% %% This is version {1.1} {2024/01/11} %% %% The list of files that compose this work can be found in the README.md file at %% https://ctan.org/pkg/tikzquests %% %%%============================================================================== %% WARNING: These are personal packs/tests %% They might and probably will change at will as needed %% %%%============================================================================== \NeedsTeXFormat{LaTeX2e}[2022/06/01] \ProvidesExplPackage {tikzquests} {2024/01/11} {1.1} {A Simple Framework for (tikz/text) Parametric Questions} \ExplSyntaxOn %%%%%%% %%% %%% Just an attempt of having my packages info in a regular way %%% Idea being: { / pkg info } for each and all. %%% %%%%%%% \keys_define:nn { tikzquests / pkg info} { name .code:n = {tikzquests} , prefix .code:n = {tikzquests} , date .code:n = {2024/01/11}, version .code:n = {1.1} , description .code:n = {A Simple Framework for (tikz/text) Parametric Questions} } \cs_if_exist:NF \PkgInfo { \NewDocumentCommand \PkgInfo {mm} { \keys_set:nn {#1 / pkg info}{#2} } \NewDocumentCommand \PkgDescription {m} { \noindent Package~ \textbf{\PkgInfo{#1}{name}}~Version:~\PkgInfo{#1}{version}~ -~ \PkgInfo{#1}{date}\par \emph{\PkgInfo{#1}{description}}~\par } } %%%%%%% %%% End of cut-n-paste %%%%%%% \newif\iftikzquests@@oldkeys % DEPRECATED, will be removed in future releases without further notice. \tikzquests@@oldkeysfalse \newif\iftikzquests@@nodefs \tikzquests@@nodefsfalse \keys_define:nn {tikzquests } { no~ alias .usage:n = load , no~ alias .bool_set:N = \l__tikzquests_noalias_bool , no~ alias .value_forbidden:n = true , xtrakeys .usage:n = load , xtrakeys .tl_set:N = \l__tikzquests_xtrakeys_tl , xtrakeys .value_required:n = true , xtraidx .usage:n = load , xtraidx .tl_set:N = \l__tikzquests_xtraidx_tl , xtraidx .value_required:n = true , undef~ color .usage:n = load , undef~ color .tl_set:N = \tikzquests@@undefcolor , % yeah... mixing styles undef~ color .value_required:n = true , undef~ color .initial:n = {red} , in~ review .usage:n = load , in~ review .bool_set:N = \l__tikzquests_inreview_bool , no~ defs .usage:n = load , no~ defs .legacy_if_gset:n = tikzquests@@nodefs , no~ defs .value_forbidden:n = true , old keys .usage:n = load , % DEPRECATED, will be removed in future releases without further notice. old keys .legacy_if_gset:n = tikzquests@@oldkeys , old keys .value_forbidden:n = true , } \ProcessKeyOptions [ tikzquests ] %%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%% %% %% %% %%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%% \msg_new:nnnn {tikzquests} {repository already defined} { (ID:#1)~Repository~ '#2'~already~defined! } { You~tried~to~create~an~already~defined~Repository:~'#2'. ~Error~Code~ ID:<#1>. } \msg_new:nnnn {tikzquests} {invalid repository} { (ID:#1)~Invalid~Repository:~ '#2' } { You~tried~to~use~an~invalid~Repository:~'#2'. ~Error~Code~ ID:<#1>. } \msg_new:nnnn {tikzquests} {invalid question} { (ID:#1)~Invalid~Question:~ '#2' } { You~tried~to~use~an~invalid~Question:~'#2'. ~Error~Code~ ID:<#1>. } \seq_new:N \l__tikzquests_repositories_seq \tl_new:N \l__tikzquests_active_repository_tl \seq_new:N \l__tikzquests_tmp_seq \tl_new:N \l__tikzquests_tmp_tl \cs_new_protected:Npn \__tikzquests_select_repository:n #1 { \prop_if_exist:cTF {l__tikzquests_ #1 _tikzrepo_prop} { \tl_set:Nn \l__tikzquests_active_repository_tl {#1} } { \msg_error:nnne {tikzquests}{invalid repository}{select~01}{#1} } } \cs_new_protected:Npn \__tikzquests_new_repository:nn #1#2 { \prop_if_exist:cTF {l__tikzquests_ #2 _tikzrepo_prop} { \msg_warning:nnne {tikzquests}{repository already defined}{new~01}{#2} } { \prop_new:c {l__tikzquests_ #2 _tikzrepo_prop} \prop_new:c {l__tikzquests_ #2 _tikzrepo_remarks_prop} \prop_new:c {l__tikzquests_ #2 _textrepo_prop} \prop_new:c {l__tikzquests_ #2 _textrepo_remarks_prop} \seq_put_right:Nn \l__tikzquests_repositories_seq {#2} } \bool_if:nT {#1} { \__tikzquests_select_repository:n {#2} } } \__tikzquests_new_repository:nn {\c_true_bool}{default} \NewDocumentCommand{\SelectRepository}{m} { \__tikzquests_select_repository:n {#1} } \NewDocumentCommand{\defNewRepository}{sm} { \__tikzquests_new_repository:nn {#1}{#2} } \NewDocumentCommand{\defQuestion}{sO{\l__tikzquests_active_repository_tl}m+mO{}} { \prop_if_exist:cTF {l__tikzquests_ #2 _tikzrepo_prop} { \bool_if:nTF {#1} { \prop_put:cnn {l__tikzquests_ #2 _textrepo_prop}{#3}{#4} \prop_put:cnn {l__tikzquests_ #2 _textrepo_remarks_prop}{#3}{#5} } { \prop_put:cnn {l__tikzquests_ #2 _tikzrepo_prop}{#3}{#4} \prop_put:cnn {l__tikzquests_ #2 _tikzrepo_remarks_prop}{#3}{#5} } } { \msg_error:nnne {tikzquests}{invalid repository}{def~quest~01}{#2} } } \NewDocumentCommand{\defQuestionAlias}{sO{\l__tikzquests_active_repository_tl}mm} { \prop_if_exist:cTF {l__tikzquests_ #2 _tikzrepo_prop} { \bool_if:NF \l__tikzquests_noalias_bool { \bool_if:nTF {#1} { \prop_get:cnNTF {l__tikzquests_ #2 _textrepo_prop}{#4} \l_tmpa_tl { \prop_put:cnn {l__tikzquests_ #2 _textrepo_prop}{#3}{\prop_item:cn {l__tikzquests_ #2 _textrepo_prop}{#4}} \prop_put:cnn {l__tikzquests_ #2 _textrepo_remarks_prop}{#3}{\prop_item:cn {l__tikzquests_ #2 _textrepo_remarks_prop}{#4}} } { \msg_error:nnnn {tikzquests}{invalid question}{alias~01}{#4} } } { \prop_get:cnNTF {l__tikzquests_ #2 _tikzrepo_prop}{#4} \l_tmpa_tl { \prop_put:cnn {l__tikzquests_ #2 _tikzrepo_prop}{#3}{\prop_item:cn {l__tikzquests_ #2 _tikzrepo_prop}{#4}} \prop_put:cnn {l__tikzquests_ #2 _tikzrepo_remarks_prop}{#3}{\prop_item:cn {l__tikzquests_ #2 _tikzrepo_remarks_prop}{#4}} } { \msg_error:nnnn {tikzquests}{invalid question}{alias~02}{#4} } } } } { \msg_error:nnne {tikzquests}{invalid repository}{alias~03}{#2} } } \cs_new_protected:Npn \__tikzquests_remarks:nnn #1#2#3 { \prop_get:cnN {l__tikzquests_ #1 _remarks_prop} {#2} \l__tikzquests_tmp_tl \tl_if_blank:eF {\l__tikzquests_tmp_tl} { {\par\footnotesize\textbf{Remarks:~}\color{\tikzquests@@undefcolor}\l__tikzquests_tmp_tl} } } \cs_new_protected:Npn \__tikzquests_inreview_remarks:nnn #1#2#3 { \bool_if:nT {\l__tikzquests_inreview_bool} { \__tikzquests_remarks:nnn {#1}{#2}{#3} \tl_if_blank:nF {#3} { {\par\footnotesize\textbf{Annotation:~}\color{\tikzquests@@undefcolor}#3} } } } \NewDocumentCommand{\ftikzQuestion}{D(){}O{\l__tikzquests_active_repository_tl}mO{}} { \begin{center} \tikzQuestion(#1)[#2]{#3}[#4] \end{center} } \NewDocumentCommand{\tikzQuestion}{D(){}O{\l__tikzquests_active_repository_tl}mO{}D<>{}} { \prop_if_exist:cTF {l__tikzquests_ #2 _tikzrepo_prop} { \prop_get:cnNTF {l__tikzquests_ #2 _tikzrepo_prop} {#3} \l__tikzquests_tmp_tl { \tl_if_blank:nTF {#1} { \begin{tikzpicture} \__tikzquests_pgfkeys:n{#4} \l__tikzquests_tmp_tl \end{tikzpicture} } { \resizebox{#1\textwidth}{!}{ \begin{tikzpicture} \__tikzquests_pgfkeys:n{#4} \l__tikzquests_tmp_tl \end{tikzpicture}} } \__tikzquests_inreview_remarks:nnn {#2 _tikzrepo}{#3}{#5} } { Invalid~Question:~#3 \msg_error:nnnn {tikzquests}{invalid question}{quest~01}{#3} } } { Invalid~Repository:~#2 \msg_error:nnne {tikzquests}{invalid repository}{quest~01}{#2} } } \cs_new_protected:Npn \__tikzquests_rawquestion:nnnnn #1#2#3#4#5 { \prop_if_exist:cTF {l__tikzquests_ #1 _ #2 _prop} { \prop_get:cnNTF {l__tikzquests_ #1 _ #2 _prop} {#3} \l__tikzquests_tmp_tl { \begingroup \__tikzquests_pgfkeys:n{#4} \l__tikzquests_tmp_tl \endgroup \__tikzquests_inreview_remarks:nnn {#1 _ #2}{#3}{#5} } { Invalid~Question:~#3 \msg_error:nnnn {tikzquests}{invalid question}{quest~02}{#3} } } { Invalid~Repository:~#1 \msg_error:nnne {tikzquests}{invalid repository}{quest~02}{#1} } } \NewDocumentCommand{\rawtikzQuestion}{O{\l__tikzquests_active_repository_tl}mO{}D<>{}} { \__tikzquests_rawquestion:nnnnn {#1}{tikzrepo}{#2}{#3}{#4} } \NewDocumentCommand{\textQuestion}{O{\l__tikzquests_active_repository_tl}mO{}D<>{}} { \__tikzquests_rawquestion:nnnnn {#1}{textrepo}{#2}{#3}{#4} } \cs_new_protected:Npn \__tikzquests_sorted_list:nnnn #1#2#3#4 { \prop_if_empty:cF {l__tikzquests_ #1 _ #2 _prop} { \seq_gclear_new:N \l__tikzquests_questions_seq \prop_map_inline:cn {l__tikzquests_ #1 _ #2 _prop} { \seq_put_right:Nn \l__tikzquests_questions_seq {##1} } \seq_sort:Nn \l__tikzquests_questions_seq { \str_compare:eNeTF { ##1 } > { ##2 } { \sort_return_swapped: } { \sort_return_same: } } \begin{description} \seq_map_inline:Nn \l__tikzquests_questions_seq { \item[#3{##1}] #4[#1]{##1} \par \bool_if:nF {\l__tikzquests_inreview_bool} { \__tikzquests_remarks:nnn {#1 _ #2}{##1}{} } \vspace{0.35ex} \hrule\relax } \end{description} } } \NewDocumentCommand{\QuestionsList}{O{}} { \tl_if_blank:nTF {#1} { \seq_set_eq:NN \l__tikzquests_tmp_seq \l__tikzquests_repositories_seq } { \seq_set_from_clist:Nn \l__tikzquests_tmp_seq {#1} } \seq_remove_duplicates:N \l__tikzquests_tmp_seq \seq_sort:Nn \l__tikzquests_tmp_seq { \str_compare:eNeTF { ##1 } > { ##2 } { \sort_return_swapped: } { \sort_return_same: } } \seq_map_inline:Nn \l__tikzquests_tmp_seq { \prop_if_exist:cTF {l__tikzquests_ ##1 _tikzrepo_prop} { {\vspace{1ex}Repository~ Name:~ \large\textbf{##1}}\vspace{0.35ex}\hrule\relax\hrule\relax {\vspace{1ex}~\hfill\emph{non~ starred~ ones~ -~ TikZ~ graphics}}\vspace{0.35ex}\hrule\relax \__tikzquests_sorted_list:nnnn {##1}{tikzrepo}{\raisebox{3em}}{\tikzQuestion(0.35)} {~\hfill\emph{starred~ ones~ -~ text/\TeX}}\vspace{0.35ex}\hrule\relax \__tikzquests_sorted_list:nnnn {##1}{textrepo}{}{\textQuestion} } { \msg_error:nnne {tikzquests}{invalid repository}{Qlist~01}{##1} } } } \tl_if_empty:NTF \l__tikzquests_xtrakeys_tl { \def\tikzquests@@xtratkey{} } { \exp_args:NNe\def\tikzquests@@xtratkey{,\l__tikzquests_xtrakeys_tl} } \tl_if_empty:NTF \l__tikzquests_xtraidx_tl { \def\tikzquests@@xtraidx{} } { \exp_args:NNe\def\tikzquests@@xtraidx{,\l__tikzquests_xtraidx_tl} } \cs_new:Npn \__tikzquests_pgfkeys:n #1 { \pgfkeys{\tikzquests@@ZPath, #1} } \NewDocumentCommand{\QuestVal}{m} { \pgfkeys{\tikzquests@@ZPath, #1} } \ExplSyntaxOff % % no easy and clean way to convert this below to expl3 (for instance underscore, under expl3 code regimè, is a letter) % \def\tikzquests@@ZPath{/tikzquests} \iftikzquests@@oldkeys% DEPRECATED, will be removed in future releases without further notice. \NewDocumentCommand{\tikzquests@@SetDef}{O{}m}{% \pgfkeys{% \tikzquests@@ZPath,% keyset/.code={% \pgfkeysalso{% default/.append style = {#2##1={#2_{#1{##1}}}},% #2/##1/.code={\csedef{#2##1}{\ensuremath{####1}}},% #2/##1/.value required,% #2##1/.code={% \ifx####1\pgfkeysnovalue% \csuse{#2##1}% \else% \csedef{#2##1}{\ensuremath{####1}}% \fi% },% #2##1*/.code={\csedef{#2##1}{\ensuremath{####1}}},% #2##1*/.value required,% #2##1 raw/.code={\csedef{#2##1}{####1}},% #2##1 raw/.value required,% }% },% setaux/.code={\pgfkeysalso{keyset/.list/.expanded={##1a,##1b,##1c,##1d,##1e,##1f,##1g,##1h,##1i,##1j,##1k,##1l,##1m,##1n,##1o,##1p,##1q,##1r,##1s,##1t,##1u,##1v,##1w,##1x,##1y,##1z}}},% setaux/.list/.expanded={,a,b\tikzquests@@xtraidx}% }% }% \else \iftikzquests@@nodefs \NewDocumentCommand{\tikzquests@@SetDef}{O{}m}{% \pgfkeys{% \tikzquests@@ZPath,% keyset/.code={% \pgfkeysalso{% #2##1/.initial={\ensuremath{#2_{#1{##1}}}},% #2##1*/.style={#2##1=\ensuremath{####1}},% #2##1*/.value required,% #2##1 raw/.style={#2##1={####1}},% #2##1 raw/.value required,% }% },% setaux/.code={\pgfkeysalso{keyset/.list/.expanded={##1a,##1b,##1c,##1d,##1e,##1f,##1g,##1h,##1i,##1j,##1k,##1l,##1m,##1n,##1o,##1p,##1q,##1r,##1s,##1t,##1u,##1v,##1w,##1x,##1y,##1z}}},% setaux/.list/.expanded={,a,b\tikzquests@@xtraidx}% }% }% \else \NewDocumentCommand{\tikzquests@@SetDef}{O{}m}{% \pgfkeys{% \tikzquests@@ZPath,% keyset/.code={% \pgfkeysalso{% default/.append style={#2##1={#2_{#1{##1}}}},% #2##1/.code={% \ifx####1\pgfkeysnovalue% \csuse{#2##1}% \else% \csedef{#2##1}{\ensuremath{####1}}% \fi% },% #2##1*/.code={\csedef{#2##1}{\ensuremath{####1}}},% #2##1*/.value required,% #2##1 raw/.code={\csedef{#2##1}{####1}},% #2##1 raw/.value required,% }% },% setaux/.code={\pgfkeysalso{keyset/.list/.expanded={##1a,##1b,##1c,##1d,##1e,##1f,##1g,##1h,##1i,##1j,##1k,##1l,##1m,##1n,##1o,##1p,##1q,##1r,##1s,##1t,##1u,##1v,##1w,##1x,##1y,##1z}}},% setaux/.list/.expanded={,a,b\tikzquests@@xtraidx}% }% }% \fi \fi \AtBeginDocument{\tikzquests@@KeysDef} \NewDocumentCommand{\tikzquests@@KeysDef}{}{% \pgfkeys{\tikzquests@@ZPath/.is family, \tikzquests@@ZPath, default/.style={},% defset/.code={\tikzquests@@SetDef{##1}},% defset/.list/.expanded={R,L,C,X,Y,Z,K,T,Q,EQ\tikzquests@@xtratkey},% defset/.code={\tikzquests@@SetDef[f_]{##1}},% defset/.list/.expanded={V,I},% default,% .unknown/.code={% \ifx##1\pgfkeysnovalue% \textbf{\emph{\color{\tikzquests@@undefcolor}\pgfkeyscurrentname}}% \else% \pgfkeysalso{\pgfkeyscurrentname/.initial={##1}} \fi% } }% }%