diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/sdaps/sdapslayout.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/sdaps/sdapslayout.dtx | 790 |
1 files changed, 790 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/sdaps/sdapslayout.dtx b/Master/texmf-dist/source/latex/sdaps/sdapslayout.dtx new file mode 100644 index 00000000000..6788e55c5a1 --- /dev/null +++ b/Master/texmf-dist/source/latex/sdaps/sdapslayout.dtx @@ -0,0 +1,790 @@ +% \iffalse meta-comment +% +% Copyright (C) 2014 by Henry Menke <henrimenke@gmail.com> +% Copyright (C) 2015-2016 by Benjamin Berg <benjamin@sipsolutions.net> +% +% This work may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.3 +% of this license or (at your option) any later version. +% The latest version of this license is in +% http://www.latex-project.org/lppl.txt +% and version 1.3 or later is part of all distributions of LaTeX +% version 2005/12/01 or later. +% +% This work has the LPPL maintenance status `maintained'. +% +% The Current Maintainer of this work is Benjamin Berg. +% +% \fi +% +% \iffalse +%<*driver> +\ProvidesFile{sdapslayout.dtx} +%</driver> +%<package>\NeedsTeXFormat{LaTeX2e}[1999/12/01] +%<package>\ProvidesPackage{sdapslayout} +%<*package> + [2015/04/10 v0.1 Initial version of SDAPS layout package] +%</package> +% +%<*driver> +\documentclass{l3doc} +\usepackage{sdapslayout}[2015/04/10] +\EnableCrossrefs +%\CodelineIndex +\RecordChanges +\begin{document} + \DocInput{sdapslayout.dtx} +\end{document} +%</driver> +% \fi +% +% \CheckSum{0} +% +% \CharacterTable +% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z +% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z +% Digits \0\1\2\3\4\5\6\7\8\9 +% Exclamation \! Double quote \" Hash (number) \# +% Dollar \$ Percent \% Ampersand \& +% Acute accent \' Left paren \( Right paren \) +% Asterisk \* Plus \+ Comma \, +% Minus \- Point \. Solidus \/ +% Colon \: Semicolon \; Less than \< +% Equals \= Greater than \> Question mark \? +% Commercial at \@ Left bracket \[ Backslash \\ +% Right bracket \] Circumflex \^ Underscore \_ +% Grave accent \` Left brace \{ Vertical bar \| +% Right brace \} Tilde \~} +% +% +% \changes{v0.1}{2015/01/14}{Initial version} +% +% \GetFileInfo{sdapslayout.dtx} +% +% \DoNotIndex{\newcommand,\newenvironment} +% +% +% \title{The \textsf{sdapslayout} package\thanks{This document +% corresponds to \textsf{sdapslayout}~\fileversion, dated \filedate.}} +% \author{Benjamin Berg \\ \texttt{benjamin@sipsolutions.net}} +% +% \maketitle +% +% \section{Documentation} +% +% Please refer to \url{https://sdaps.org/class-doc} for documentation. +% +% \section{Implementation} +% +% This package uses the \LaTeX3 language internally, so we need to enable it. +% \begin{macrocode} +% We need at least 2011-08-23 for \keys_set_known:nnN +\RequirePackage{expl3}[2011/08/23] +%\RequirePackage{xparse} +\ExplSyntaxOn +% \end{macrocode} +% +% And we need a number of other packages. +% \begin{macrocode} +\ExplSyntaxOff + +\RequirePackage{sdapsbase} +\RequirePackage{sdapsarray} +\RequirePackage{xparse} + + +\ExplSyntaxOn + +% \end{macrocode} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% +% \subsection{Choice Question Layout} +% +% \subsubsection{Choice Question Matrix Layout} +% +% The following macros provide the funcitonality to layout choice questions in +% a matrix like fashion. +% +% \begin{macrocode} + +\tl_new:N \l_sdaps_choicearray_qobject_type_tl +\bool_new:N \l_sdaps_choicearray_horizontal_bool +\tl_new:N \l_sdaps_choicearray_var_tl +\tl_new:N \l_sdaps_choicearray_text_tl +\tl_new:N \l_sdaps_choicearray_layouter_tl +\tl_new:N \l_sdaps_choicearray_align_tl +\tl_new:N \l_sdaps_choicearray_extra_tl +\tl_new:N \l_sdaps_choicearray_type_tl +\tl_new:N \l_sdaps_choice_var_tl +\tl_new:N \l_sdaps_choice_val_tl +\tl_new:N \l_sdaps_choice_text_tl +\tl_new:N \l_sdaps_question_var_tl +\tl_new:N \l_sdaps_question_text_tl +\clist_new:N \l_sdaps_question_range_clist +\int_new:N \g_sdaps_choices_box_int +\seq_new:N \g_sdaps_choices_filter_seq +\seq_new:N \g_sdaps_choices_cell_seq +\seq_new:N \g_sdaps_choices_text_seq + +\keys_define:nn { sdaps / choicearray } +{ + horizontal .bool_set:N = \l_sdaps_choicearray_horizontal_bool, + horizontal .default:n = true, + horizontal .initial:n = true, + vertical .bool_set_inverse:N = \l_sdaps_choicearray_horizontal_bool, + vertical .default:n = true, + var .tl_set:N = \l_sdaps_choicearray_var_tl, + text .tl_set:N = \l_sdaps_choicearray_text_tl, + layouter .tl_set:N = \l_sdaps_choicearray_layouter_tl, + layouter .initial:n = default, + align .tl_set:N = \l_sdaps_choicearray_align_tl, + align .initial:n = { }, + + type .choices:nn = { multichoice, singlechoice } { \tl_set:Nx \l_sdaps_choicearray_type_tl { \l_keys_choice_tl } }, + type .initial:n = { multichoice }, + + singlechoice .meta:n = { type=singlechoice }, + multichoice .meta:n = { type=multichoice }, + + noalign .meta:n = { align= }, +} + +\keys_define:nn { sdaps / choicearray / choice } +{ + var .tl_set:N = \l_sdaps_choice_var_tl, + val .tl_set:N = \l_sdaps_choice_val_tl, + text .tl_set:N = \l_sdaps_choice_text_tl, +} + +\keys_define:nn { sdaps / choicearray / question } +{ + var .tl_set:N = \l_sdaps_question_var_tl, + text .tl_set:N = \l_sdaps_question_text_tl, + + range .clist_set:N = \l_sdaps_question_range_clist, + range .initial:n = {...} +} + +\cs_new_protected_nopar:Npn \_sdaps_choicearray_preprocess:nn #1#2 +{ + \keys_set_known:nnN { sdaps / choicearray } { #1 } \l_sdaps_choicearray_extra_tl + + \tl_if_empty:NTF \l_sdaps_choicearray_text_tl { + \sdaps_qobject_begin:nnn { choicearray } { Head } { #2 } + } { + \sdaps_qobject_begin:nnV { choicearray } { Head } \l_sdaps_choicearray_text_tl + } + + \tl_if_empty:NF \l_sdaps_choicearray_var_tl { + \sdaps_qobject_append_var:V \l_sdaps_choicearray_var_tl + } + + \sdaps_checkbox_set_type:V \l_sdaps_choicearray_type_tl + \tl_if_eq:VnTF \l_sdaps_choicearray_type_tl { multichoice } { + \tl_set:Nn \l_sdaps_choicearray_qobject_type_tl { Choice } + } { + \tl_set:Nn \l_sdaps_choicearray_qobject_type_tl { Option } + } +} +\cs_generate_variant:Nn \_sdaps_choicearray_preprocess:nn { Vn } + +\cs_new_protected_nopar:Npn \_sdaps_choicearray_postprocess: +{ + \sdaps_qobject_end:n { choicearray } +} + +\cs_new_protected_nopar:Npn \_sdaps_choicearray_process_choice_insert_tail_after:w { + \bgroup + \group_insert_after:N \_sdaps_choicearray_process_choice_tail: + \sdaps_array_nested_alignenv: + \tex_let:D\next= +} + +\cs_new_protected_nopar:Nn \_sdaps_choicearray_process_choice_tail: { + \ignorespaces +} + +\cs_new_nopar:Nn \_sdaps_choicearray_grab_choice:n { + \seq_gput_right:Nn \g_sdaps_choices_text_seq { #1 } + \group_begin: + \sdaps_array_nested_alignenv: + #1 + \group_end: + \_sdaps_choicearray_process_choice_tail: +} + +\cs_new_nopar:Npn \_sdaps_choicearray_process_choice:nw #1 +{ + % This modifies grouping so it has to be at the start + \sdaps_array_alignment: + \leavevmode + + \tl_clear:N \l_sdaps_choice_var_tl + \tl_clear:N \l_sdaps_choice_val_tl + \tl_clear:N \l_sdaps_choice_text_tl + + \keys_set:nn { sdaps / choicearray / choice } { #1 } + + \int_gincr:N \g_sdaps_choices_box_int + + \tl_if_empty:NT \l_sdaps_choice_var_tl { + % Prefix with _ to force prefixing with generated variable + \tl_set:Nx \l_sdaps_choice_var_tl { \int_use:N \g_sdaps_choices_box_int } + } + \tl_if_empty:NT \l_sdaps_choice_val_tl { + \tl_set:Nx \l_sdaps_choice_val_tl { \int_use:N \g_sdaps_choices_box_int } + } + + \tl_if_eq:VnTF \l_sdaps_choicearray_type_tl { multichoice } { + \seq_gput_right:NV \g_sdaps_choices_filter_seq \l_sdaps_choice_var_tl + } { + \seq_gput_right:NV \g_sdaps_choices_filter_seq \l_sdaps_choice_val_tl + } + + \seq_gput_right:Nx \g_sdaps_choices_cell_seq { \exp_not:n { \sdaps_checkbox:nn } { _ \l_sdaps_choice_var_tl } { \l_sdaps_choice_val_tl } } + + \tl_if_empty:NTF \l_sdaps_choice_text_tl { + % We need to leave a command in the stream that grabs the next parameter + % and outputs it immediately + \cs_set_eq:NN \l_tmpa_token \_sdaps_choicearray_grab_choice:n + } { + % Nothing else to do + \seq_gput_right:NV \g_sdaps_choices_text_seq { \l_sdaps_choice_text_tl } + \cs_set_eq:NN \l_tmpa_token \_sdaps_choicearray_process_choice_insert_tail_after:w + } + \l_tmpa_token +} +\cs_generate_variant:Nn \_sdaps_choicearray_process_choice:nw { Vw } + +\cs_new_protected_nopar:Nn \_sdaps_choicearray_process_question_grab:n { + \tl_set:Nn \l_sdaps_question_text_tl { #1 } + + \_sdaps_choicearray_process_question_head: + + \group_begin: + \sdaps_array_nested_alignenv: + #1 + \group_end: + + \_sdaps_choicearray_process_question_tail: +} + +\cs_new_protected_nopar:Npn \_sdaps_choicearray_process_question_inline:w { + \_sdaps_choicearray_process_question_head: + \bgroup + \group_insert_after:N \_sdaps_choicearray_process_question_tail: + \sdaps_array_nested_alignenv: + \tex_let:D\next= +} + +\cs_new_protected_nopar:Nn \_sdaps_choicearray_process_question_head: { + \sdaps_qobject_begin:nnV { choicearray_question } \l_sdaps_choicearray_qobject_type_tl \l_sdaps_question_text_tl + + \tl_if_empty:NF \l_sdaps_question_var_tl { + \sdaps_qobject_append_var:V \l_sdaps_question_var_tl + } +} + +\cs_new_protected_nopar:Nn \_sdaps_choicearray_process_question_tail: { + \seq_gclear:N \g_tmpa_seq + % l_tmpa_bool is whether we are in a run (i.e. ...) + \bool_set_false:N \l_tmpa_bool + + \clist_gset_eq:NN \g_tmpa_clist \l_sdaps_question_range_clist + \clist_gpop:NN \g_tmpa_clist \l_tmpa_tl + + \seq_map_inline:Nn \g_sdaps_choices_filter_seq { + \tl_if_eq:VnT \l_tmpa_tl { ... } { + \bool_set_true:N \l_tmpa_bool + \clist_gpop:NN \g_tmpa_clist \l_tmpa_tl + } + + \tl_if_eq:VnTF \l_tmpa_tl { ##1 } { + \seq_gput_right:Nn \g_tmpa_seq { \c_true_bool } + \bool_set_false:N \l_tmpa_bool + \clist_gpop:NN \g_tmpa_clist \l_tmpa_tl + } { + % Append if we are handling a run of items and the current item is not + % the last one. + \bool_if:NTF \l_tmpa_bool { + \seq_gput_right:Nn \g_tmpa_seq { \c_true_bool } + } { + % Otherwise, ignore this item + \seq_gput_right:Nn \g_tmpa_seq { \c_false_bool } + } + } + } + + \seq_gset_eq:NN \g_tmpb_seq \g_tmpa_seq + + \seq_map_inline:Nn \g_sdaps_choices_text_seq { + \seq_gpop_left:NN \g_tmpa_seq \l_tmpa_tl + \tl_if_eq:VnT \l_tmpa_tl { \c_true_bool } { + \sdaps_answer:f { ##1 } + } + } + + \seq_map_inline:Nn \g_sdaps_choices_cell_seq { + \sdaps_array_alignment: + + \seq_gpop_left:NN \g_tmpb_seq \l_tmpa_tl + \tl_if_eq:VnT \l_tmpa_tl { \c_true_bool } { + ##1 + } + } + + \sdaps_qobject_end:n { choicearray_question } + \ignorespaces +} + +\cs_new_nopar:Npn \_sdaps_choicearray_process_question:nw #1 +{ + \sdaps_array_newline: + \leavevmode + + \keys_set:nn { sdaps / choicearray / question } { #1 } + + \tl_if_empty:NTF \l_sdaps_question_text_tl { + % We need to leave a command in the stream that grabs the next parameter, + % outputs it again, and finishes the question. + \cs_set_eq:NN \l_tmpa_token \_sdaps_choicearray_process_question_grab:n + } { + % Insert the question around the next argument + \cs_set_eq:NN \l_tmpa_token \_sdaps_choicearray_process_question_inline:w + } + \l_tmpa_token +} +\cs_generate_variant:Nn \_sdaps_choicearray_process_question:nw { Vw } + + + +% +% \end{macrocode} +% +% +% \subsection{Range Question Layout} +% +% \subsubsection{Range Question Matrix Layout} +% +% The following macros provide the functionality to layout range/option +% questions in a matrix like fashion. +% +% \begin{macrocode} + + +\tl_new:N \l_sdaps_rangearray_var_tl +\tl_new:N \l_sdaps_rangearray_text_tl +\tl_new:N \l_sdaps_rangearray_align_tl +\tl_new:N \l_sdaps_rangearray_extra_tl +\int_new:N \l_sdaps_rangearray_rangecount_int +\bool_new:N \l_sdaps_rangearray_other_bool +\tl_new:N \g_sdaps_question_var_tl +\tl_new:N \g_sdaps_question_text_tl +\tl_new:N \g_sdaps_question_lowertext_tl +\tl_new:N \g_sdaps_question_uppertext_tl +\tl_new:N \g_sdaps_question_othertext_tl + +\keys_define:nn { sdaps / rangearray } +{ + var .tl_set:N = \l_sdaps_rangearray_var_tl, + text .tl_set:N = \l_sdaps_rangearray_text_tl, + count .int_set:N = \l_sdaps_rangearray_rangecount_int, + count .initial:n = 5, + align .tl_set:N = \l_sdaps_rangearray_align_tl, + align .initial:n = { }, + other .bool_set:N = \l_sdaps_rangearray_other_bool, + other .default:n = true, + other .initial:n = false, +} + +\keys_define:nn { sdaps / rangearray / question } +{ + var .tl_gset:N = \g_sdaps_question_var_tl, + text .tl_gset:N = \g_sdaps_question_text_tl, + upper .tl_gset:N = \g_sdaps_question_uppertext_tl, + lower .tl_gset:N = \g_sdaps_question_lowertext_tl, + other .tl_gset:N = \g_sdaps_question_othertext_tl, +} + +\cs_new_protected_nopar:Npn \_sdaps_rangearray_preprocess:nn #1#2 +{ + \keys_set_known:nnN { sdaps / rangearray } { #1 } \l_sdaps_rangearray_extra_tl + + \tl_if_empty:NTF \l_sdaps_rangearray_text_tl { + \sdaps_qobject_begin:nnn { rangearray } { Head } { #2 } + } { + \sdaps_qobject_begin:nnV { rangearray } { Head } \l_sdaps_rangearray_text_tl + } + + \sdaps_checkbox_set_type:n { singlechoice } + + \tl_if_empty:NF \l_sdaps_rangearray_var_tl { + \sdaps_qobject_append_var:V \l_sdaps_rangearray_var_tl + } +} +\cs_generate_variant:Nn \_sdaps_rangearray_preprocess:nn { Vn } + +\cs_new_protected_nopar:Npn \_sdaps_rangearray_postprocess: +{ + \sdaps_qobject_end:n { rangearray } +} + +% Before/After the different parts + +\cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_before_question: { + \sdaps_array_newline: + % Note: This needs to be after sdaps_array_newline as the command may be + % discarded otherwise (i.e. it does not make it into the output stream) + % We also need to leave vmode here + \leavevmode + \sdaps_qobject_begin:nnV { rangearray_question } { Range } \g_sdaps_question_text_tl + + \tl_if_empty:NF \g_sdaps_question_var_tl { + \sdaps_qobject_append_var:V \g_sdaps_question_var_tl + } + + \ignorespaces +} + +\cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_before_lower: { + % right align + \sdaps_array_alignment: + \leavevmode + \sdaps_range:nnV { lower } { 0 } \g_sdaps_question_lowertext_tl + \sdaps_if_rtl:F { + \hfill + } + \ignorespaces +} + +\cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_before_upper: { + \sdaps_array_alignment: + \leavevmode + \sdaps_range:nnV { upper } { \l_sdaps_rangearray_rangecount_int - 1 } \g_sdaps_question_uppertext_tl + \sdaps_if_rtl:T { + \hfill + } + \ignorespaces +} + +\cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_before_other: { + % Insert an extra empty column for further spacing + \sdaps_array_alignment: + \sdaps_array_alignment: + \leavevmode + \sdaps_answer:V \g_sdaps_question_othertext_tl + \sdaps_if_rtl:TF { + \hfill + } { + \sdaps_checkbox:nn { } { 0 } {} ~ {} + } + \ignorespaces +} + + + +\cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_after_question: { + % Insert an extra empty column for further spacing + \sdaps_array_alignment: + \tl_if_empty:NTF \g_sdaps_question_lowertext_tl { + \cs_set_eq:NN \l_tmpa_token \_sdaps_rangearray_process_question_grab_lower:n + } { + \cs_set_eq:NN \l_tmpa_token \_sdaps_rangearray_process_question_inline_lower:w + } + \l_tmpa_token +} + +\cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_after_lower: { + % Insert the option checkbox column + \sdaps_if_rtl:T { + \hfill\kern 0pt + } + \sdaps_array_alignment: + \leavevmode + % Seems like right to left writing mode is not started without a paragraph + \sdaps_if_rtl:T { \beginR } + % Assume we have at least one checkbox + \sdaps_checkbox:nn { } { 1 } + \int_step_inline:nnnn { 2 } { 1 } { \l_sdaps_rangearray_rangecount_int } { + \hspace{1em} \sdaps_checkbox:nn { } { ##1 } + } + \sdaps_if_rtl:T { \endR } + + \tl_if_empty:NTF \g_sdaps_question_uppertext_tl { + \cs_set_eq:NN \l_tmpa_token \_sdaps_rangearray_process_question_grab_upper:n + } { + \cs_set_eq:NN \l_tmpa_token \_sdaps_rangearray_process_question_inline_upper:w + } + \l_tmpa_token +} + +\cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_after_upper: { + \sdaps_if_rtl:F { + \hfill\kern 0pt + } + + \bool_if:NTF \l_sdaps_rangearray_other_bool { + \tl_if_empty:NTF \g_sdaps_question_othertext_tl { + \cs_set_eq:NN \l_tmpa_token \_sdaps_rangearray_process_question_grab_other:n + } { + \cs_set_eq:NN \l_tmpa_token \_sdaps_rangearray_process_question_inline_other:w + } + } { + \cs_set_eq:NN \l_tmpa_token \_sdaps_rangearray_process_question_finish: + } + \l_tmpa_token +} + +\cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_after_other: { + \sdaps_if_rtl:TF { + {} ~ \sdaps_checkbox:nn { } { 0 } {} + } { + \hfill\kern 0pt + } + \ignorespaces +} + +\cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_finish: { + \sdaps_qobject_end:n { rangearray_question } + \ignorespaces +} + +% Processors for inline processing/grabbing the argument + +\cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_grab_question:n { + \tl_gset:Nn \g_sdaps_question_text_tl { #1 } + + \_sdaps_rangearray_process_question_before_question: + \group_begin: + \sdaps_array_nested_alignenv: + #1 + \group_end: + \_sdaps_rangearray_process_question_after_question: +} + +\cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_grab_lower:n { + \tl_gset:Nn \g_sdaps_question_lowertext_tl { #1 } + + \_sdaps_rangearray_process_question_before_lower: + \group_begin: + \sdaps_array_nested_alignenv: + #1 + \group_end: + \_sdaps_rangearray_process_question_after_lower: +} + +\cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_grab_upper:n { + \tl_gset:Nn \g_sdaps_question_uppertext_tl { #1 } + + \_sdaps_rangearray_process_question_before_upper: + \group_begin: + \sdaps_array_nested_alignenv: + #1 + \group_end: + \_sdaps_rangearray_process_question_after_upper: +} + +\cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_grab_other:n { + \tl_gset:Nn \g_sdaps_question_othertext_tl { #1 } + + % If the text is empty, assume that this particular question does not have + % an alternative choice. Note that this column might not exist and this + % macro will not even be called in that case. + % If we skip the optional "other" option then we still need to insert the + % alignment to create the column. + \tl_if_empty:NTF \g_sdaps_question_othertext_tl { + \sdaps_array_alignment: + \leavevmode + \ignorespaces + } { + \_sdaps_rangearray_process_question_before_other: + \group_begin: + \sdaps_array_nested_alignenv: + #1 + \group_end: + \_sdaps_rangearray_process_question_after_other: + } + \_sdaps_rangearray_process_question_finish: +} + + + +\cs_new_protected_nopar:Npn \_sdaps_rangearray_process_question_inline_question:w { + \_sdaps_rangearray_process_question_before_question: + \bgroup + \group_insert_after:N \_sdaps_rangearray_process_question_after_question: + \sdaps_array_nested_alignenv: + \tex_let:D\next= +} + +\cs_new_protected_nopar:Npn \_sdaps_rangearray_process_question_inline_lower:w { + \_sdaps_rangearray_process_question_before_lower: + \bgroup + \group_insert_after:N \_sdaps_rangearray_process_question_after_lower: + \tex_let:D\next= +} + +\cs_new_protected_nopar:Npn \_sdaps_rangearray_process_question_inline_upper:w { + \_sdaps_rangearray_process_question_before_upper: + \bgroup + \group_insert_after:N \_sdaps_rangearray_process_question_after_upper: + \tex_let:D\next= +} + +\cs_new_protected_nopar:Npn \_sdaps_rangearray_process_question_inline_other:w { + \_sdaps_rangearray_process_question_before_other: + % If we reach this macro then a text has been set for the other item. This + % means we never need to ignore the "other" parameter at this point. + \bgroup + \group_insert_after:N \_sdaps_rangearray_process_question_after_other: + \group_insert_after:N \_sdaps_rangearray_process_question_finish: + \tex_let:D\next= +} + + + + +\cs_new_nopar:Npn \_sdaps_rangearray_process_question:nw #1 +{ + % Is there a better way other than clearing these before parsing? + \tl_gclear:N \g_sdaps_question_var_tl + \tl_gclear:N \g_sdaps_question_text_tl + \tl_gclear:N \g_sdaps_question_uppertext_tl + \tl_gclear:N \g_sdaps_question_lowertext_tl + \tl_gclear:N \g_sdaps_question_othertext_tl + + \keys_set:nn { sdaps / rangearray / question } { #1 } + + \tl_if_empty:NTF \g_sdaps_question_text_tl { + % We need to leave a command in the stream that grabs the next parameter, + % outputs it again, and finishes the question. + \cs_set_eq:NN \l_tmpa_token \_sdaps_rangearray_process_question_grab_question:n + } { + % We need to generate the question after the next group stops + \cs_set_eq:NN \l_tmpa_token \_sdaps_rangearray_process_question_inline_question:w + } + \l_tmpa_token +} +\cs_generate_variant:Nn \_sdaps_rangearray_process_question:nw { Vw } + + + +% +% \end{macrocode} +% +% +% +% \subsection{Export user facing environments} +% +% \begin{macrocode} +% + + +\newenvironment { choicearray } [ 2 ] [] +{ + \group_begin: + + \sdaps_context_get:nN { choicearray } \l_tmpa_tl + \tl_if_eq:NNT \l_tmpa_tl \q_no_value { + \tl_set:Nn \l_tmpa_tl {} + } + + \tl_if_empty:nF { #1 } { + \tl_if_empty:NTF \l_tmpa_tl { + \tl_set:Nn \l_tmpa_tl { #1 } + } { + \tl_set:Nf \l_tmpa_tl { \l_tmpa_tl, #1 } + } + } + + \_sdaps_choicearray_preprocess:Vn \l_tmpa_tl { #2 } + % Clear the variables + \seq_gclear:N \g_sdaps_choices_filter_seq + \seq_gclear:N \g_sdaps_choices_cell_seq + \seq_gclear:N \g_sdaps_choices_text_seq + + \int_gzero:N \g_sdaps_choices_box_int + + % Define new commands + \newcommand \choice [ 1 ] [] { + \_sdaps_choicearray_process_choice:nw { ##1 } + } + \newcommand \question [ 1 ] [] { + \_sdaps_choicearray_process_question:nw { ##1 } + } + + \group_begin: + + \tl_set:Nx \l_tmpb_tl {keepenv,layouter=\tl_use:N\l_sdaps_choicearray_layouter_tl,align=\l_sdaps_choicearray_align_tl\bool_if:NF\l_sdaps_choicearray_horizontal_bool{,flip},\l_sdaps_choicearray_extra_tl} + \expandafter\sdapsarray\expandafter[\l_tmpb_tl] +} +{ + \endsdapsarray + \group_end: + % Process keys + \_sdaps_choicearray_postprocess: + + \group_end: +} + +\newenvironment { optionarray } [ 2 ] [] +{ + \choicearray[singlechoice,#1] { #2 } +} +{ + \endchoicearray +} + +\newenvironment { rangearray } [ 2 ] [] +{ + \group_begin: + + \sdaps_context_get:nN { rangearray } \l_tmpa_tl + \tl_if_eq:NNT \l_tmpa_tl \q_no_value { + \tl_set:Nn \l_tmpa_tl {} + } + + \tl_if_empty:nF { #1 } { + \tl_if_empty:NTF \l_tmpa_tl { + \tl_set:Nn \l_tmpa_tl { #1 } + } { + \tl_set:Nf \l_tmpa_tl { \l_tmpa_tl, #1 } + } + } + + \_sdaps_rangearray_preprocess:Vn \l_tmpa_tl { #2 } + + \newcommand \range [ 1 ] [] { + \_sdaps_rangearray_process_question:nw { ##1 } + } + + \group_begin: + + \tl_set:Nx \l_tmpb_tl {keepenv,align=\l_sdaps_rangearray_align_tl,\l_sdaps_rangearray_extra_tl} + \expandafter\sdapsarray\expandafter[\l_tmpb_tl] +} +{ + \endsdapsarray + \group_end: + % Process keys + \_sdaps_rangearray_postprocess: + + \group_end: +} + + +\ExplSyntaxOff + +% +% \end{macrocode} +% +% \iffalse +% \PrintChanges +% \PrintIndex +% \fi +% +% \Finale +\endinput |