% -------------------------------------------------------------------------- % the TASKS package % % lists with columns filled horizontally % % -------------------------------------------------------------------------- % Clemens Niederberger % Web: https://github.com/cgnieder/tasks/ % E-Mail: contact@mychemistry.eu % -------------------------------------------------------------------------- % Copyright 2013--2022 Clemens Niederberger % % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3c % 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.3c or later is part of all distributions of LaTeX % version 2008/05/04 or later. % % This work has the LPPL maintenance status `maintained'. % % The Current Maintainer of this work is Clemens Niederberger. % -------------------------------------------------------------------------- % If you have any ideas, questions, suggestions or bugs to report, please % feel free to contact me. % -------------------------------------------------------------------------- \RequirePackage {expl3,xparse,xtemplate} \ExplSyntaxOn \tl_const:Nn \c_tasks_date_tl {2022/01/08} \tl_const:Nn \c_tasks_version_major_number_tl {1} \tl_const:Nn \c_tasks_version_minor_number_tl {4} \tl_const:Nn \c_tasks_version_subrelease_tl {a} \tl_const:Nx \c_tasks_version_number_tl { \c_tasks_version_major_number_tl . \c_tasks_version_minor_number_tl } \tl_const:Nx \c_tasks_version_tl { \c_tasks_version_number_tl \c_tasks_version_subrelease_tl } \tl_const:Nn \c_tasks_info_tl {lists~ with~ columns~ filled~ horizontally} \ProvidesExplPackage {tasks} {\c_tasks_date_tl} {\c_tasks_version_tl} {\c_tasks_info_tl} % -------------------------------------------------------------------------- % variants of kernel functions: \cs_generate_variant:Nn \tl_if_eq:nnTF {V} \cs_generate_variant:Nn \tl_if_eq:nnT {V} \cs_generate_variant:Nn \tl_if_eq:nnF {V} \cs_generate_variant:Nn \coffin_attach:NnnNnnnn {NnnNx} \cs_generate_variant:Nn \tl_set_rescan:Nnn {NnV} \cs_generate_variant:Nn \tl_set:Nn {cV} \cs_generate_variant:Nn \hbox_set:Nn {NV} \cs_generate_variant:Nn \msg_warning:nnnn {nnV,nnnx} \cs_generate_variant:Nn \tl_replace_all:Nnn {Nne} % -------------------------------------------------------------------------- \msg_new:nnn {tasks} {width-too-small} { The~ width~ of~ `#1'~ is~ too~ small~ \msg_line_context: .~ Please~ set~ it~ at~ least~ to~ #2 pt. } \msg_new:nnn {tasks} {no-item} { You've~ placed \\ \\ #1 \\ \\ before~ the~ first~ #2~ \msg_line_context: .~ I~ will~ throw~ it~ away~ and~ ignore~ it~ for~ the~ rest~ of~ the~ list. } \msg_new:nnn {tasks} {deprecated} { You've~ tried~ setting~ #1~ `#2'~ \msg_line_context: .~ However,~ #1~ `#2'~ is~ deprecated.~ \tl_if_blank:nF {#3} {Please~ use~ #1~ `#3'~ instead.~} Refer~ to~ the~ manual~ for~ details. } % -------------------------------------------------------------------------- \cs_new_protected:Npn \tasks_deprecated:NN #1#2 { \cs_undefine:N #1 \cs_new:Npn #1 { \msg_warning:nnnnn {tasks} {deprecated} {command} {#1} {#2} #2 } } % -------------------------------------------------------------------------- % variables: \seq_new:N \l__tasks_seq \int_new:N \g__tasks_total_items_int \int_new:N \l__tasks_columns_int \int_new:N \g__tasks_rows_int \int_new:N \g__tasks_current_col_num_int \int_new:N \g__tasks_current_row_num_int \int_new:N \l__tasks_item_columns_int \int_new:N \g__tasks_env_int \int_new:N \l__tasks_start_int \bool_new:N \l__tasks_resume_bool \bool_new:N \l__tasks_load_tasks_bool \bool_new:N \l__tasks_label_width_bool \bool_new:N \l__tasks_item_indent_bool \bool_new:N \l__tasks_label_offset_bool \bool_new:N \l__tasks_custom_label_bool \bool_new:N \l__tasks_custom_ref_bool \bool_new:N \l__tasks_custom_label_format_bool \bool_new:N \l__tasks_custom_after_item_skip_bool \bool_new:N \l__tasks_debug_bool \bool_new:N \l__tasks_item_full_line_bool \bool_new:N \l__tasks_item_rest_of_line_bool \bool_new:N \l__tasks_measuring_bool \tl_new:N \l__tasks_instance_tl \tl_new:N \l__tasks_label_tl \tl_new:N \l__tasks_custom_label_tl \tl_new:N \l__tasks_ref_tl \tl_new:N \l__tasks_custom_ref_tl \tl_new:N \l__tasks_label_format_tl \tl_new:N \l__tasks_custom_label_format_tl \tl_new:N \l__tasks_counter_tl \tl_new:N \l__tasks_item_format_tl \tl_new:N \l__tasks_custom_item_format_tl \tl_new:N \l__tasks_item_fill_left_tl \tl_new:N \l__tasks_item_fill_right_tl \tl_new:N \l__tasks_label_align_tl \tl_new:N \l__tasks_item_tl \tl_new:N \l__tasks_tmp_label_tl \cs_set:Nx \__tasks_restore_dollar: { \char_set_catcode:nn {36} { \char_value_catcode:n {36} } } \char_set_catcode_alignment:N \$ \tl_const:Nn \c__tasks_default_label_tl {$tasks$default$label$} \__tasks_restore_dollar: \dim_new:N \l__tasks_item_indent_dim \dim_new:N \l__tasks_item_default_indent_dim \dim_new:N \l__tasks_item_width_dim \dim_new:N \l__tasks_label_width_dim \dim_new:N \l__tasks_label_default_width_dim \dim_new:N \l__tasks_label_offset_dim \dim_new:N \l__tasks_label_default_offset_dim \dim_new:N \l__tasks_column_sep_dim \dim_new:N \l__tasks_correction_dim \dim_new:N \l__tasks_full_width_dim \skip_new:N \l__tasks_after_item_skip \skip_new:N \l__tasks_custom_after_item_skip \skip_new:N \l__tasks_before_list_skip \skip_new:N \l__tasks_after_list_skip \coffin_new:N \l__tasks_item_coffin \coffin_new:N \l__tasks_label_coffin \newcounter {task} % temporary variables: \int_new:N \l__tasks_tmpa_int \int_new:N \l__tasks_tmpb_int \tl_new:N \l__tasks_tmpa_tl \coffin_new:N \l__tasks_tmpa_coffin \box_new:N \l__tasks_tmpa_box \bool_new:N \l__tasks_tmpa_bool \cs_new:Npn \__tasks_debug:n #1 { \bool_if:NTF \l__tasks_debug_bool { \fbox {#1} } { \use:n {#1} } } \prg_new_conditional:Npnn \tasks_if_measuring: {p,T,F,TF} { \bool_if:NTF \l__tasks_measuring_bool { \prg_return_true: } { \prg_return_false: } } \DeclareExpandableDocumentCommand \tasksifmeasuringTF {+m+m} { \tasks_if_measuring:TF {#1} {#2} } \DeclareExpandableDocumentCommand \tasksifmeasuringT {+m} { \tasks_if_measuring:T {#1} } \DeclareExpandableDocumentCommand \tasksifmeasuringF {+m} { \tasks_if_measuring:F {#1} } % -------------------------------------------------------------------------- % #1: instance % #2: number of columns % #3: item separator % #4: environment body \cs_new_protected:Npn \tasks_environment:nnnn #1#2#3#4 { \bool_if:NT \l__tasks_debug_bool { \dim_set:Nn \fboxsep {0pt} } \seq_set_split:Nnn \l__tasks_seq {#3} {#4} % remove the first (empty) item: \seq_pop_left:NN \l__tasks_seq \l__tasks_tmpa_tl \tl_if_blank:VF \l__tasks_tmpa_tl { \msg_warning:nnVn {tasks}{no-item} \l__tasks_tmpa_tl {#3} } \int_gset:Nn \g__tasks_total_items_int { \seq_count:N \l__tasks_seq } \UseInstance {tasks} {#1} { \g__tasks_total_items_int } {#2} { } % just to be sure: \seq_clear:N \l__tasks_seq } \cs_generate_variant:Nn \tasks_environment:nnnn {V} % #1: label % #2: item format % #3: item \cs_new_protected:Npn \__tasks_task:nnn #1#2#3 { % start a new item line if \l__tasks_item_full_line_bool \bool_if:NT \l__tasks_item_full_line_bool { % add skip if we were in the middle of a line, i.e., in horizontal % mode: \mode_if_horizontal:T { \skip_vertical:N \l__tasks_after_item_skip } \tasks_new_row: } % step column position: \int_gincr:N \g__tasks_current_col_num_int \dim_set:Nn \l__tasks_item_width_dim { \bool_if:NTF \l__tasks_item_full_line_bool { \l__tasks_full_width_dim } { ( \l__tasks_full_width_dim - \l__tasks_columns_int \l__tasks_column_sep_dim + \l__tasks_column_sep_dim ) / \l__tasks_columns_int } - \l__tasks_item_indent_dim \bool_if:NT \l__tasks_debug_bool { -2\fboxrule } } \dim_set:Nn \l_tmpa_dim { \l__tasks_columns_int \l__tasks_item_width_dim + \l__tasks_columns_int \l__tasks_column_sep_dim - \l__tasks_column_sep_dim + \l__tasks_columns_int \l__tasks_item_indent_dim \bool_if:NT \l__tasks_debug_bool { +\l__tasks_columns_int\fboxrule } \bool_if:NT \l__tasks_debug_bool { +\l__tasks_columns_int\fboxrule } } \dim_compare:nNnT { \l_tmpa_dim } > { \l__tasks_full_width_dim } { \dim_sub:Nn \l__tasks_item_width_dim { \l__tasks_correction_dim } } \__tasks_gset_rows_num:NN \g__tasks_total_items_int \l__tasks_columns_int % set \g__tasks_current_col_num_int to 1 if at the start of a row, % then also step \g__tasks_current_row_num_int : \int_compare:nNnT { \g__tasks_current_col_num_int } > { \l__tasks_columns_int } { \int_gset:Nn \g__tasks_current_col_num_int {1} \int_gincr:N \g__tasks_current_row_num_int } % if the next item fills rest of line: \bool_if:NT \l__tasks_item_rest_of_line_bool { % number of remaining columns: \int_set:Nn \l__tasks_tmpa_int { \l__tasks_columns_int - \g__tasks_current_col_num_int + 1 } % check requested column number and adjust: \int_compare:nNnF { \l__tasks_item_columns_int } = {0} { \int_compare:nNnTF { \l__tasks_tmpa_int } > { \l__tasks_item_columns_int } { \int_set_eq:NN \l__tasks_tmpa_int \l__tasks_item_columns_int } { \int_zero:N \l__tasks_item_columns_int } \bool_lazy_and:nnT { \l__tasks_item_rest_of_line_bool } { !\int_compare_p:nNn { \l__tasks_item_columns_int } = {0} } { \int_gadd:Nn \g__tasks_current_col_num_int { \l__tasks_item_columns_int -1 } \int_gadd:Nn \g__tasks_total_items_int { \l__tasks_item_columns_int - 1 } } } \int_set:Nn \l__tasks_tmpb_int { \l__tasks_tmpa_int - 1 } \dim_set:Nn \l__tasks_item_width_dim { \l__tasks_tmpa_int \l__tasks_item_width_dim + \l__tasks_tmpb_int \l__tasks_column_sep_dim + \l__tasks_tmpb_int \l__tasks_item_indent_dim \bool_if:NT \l__tasks_debug_bool { + \int_eval:n { \l__tasks_tmpb_int * 2 } \fboxrule } } } % set the item box: \hcoffin_set:Nn \l__tasks_item_coffin { \vcoffin_set:Nnn \l__tasks_tmpa_coffin { \l__tasks_item_width_dim } { \__tasks_setup: #2 {#3} \mode_if_horizontal:T { \strut } } \__tasks_debug:n { \coffin_typeset:Nnnnn \l__tasks_tmpa_coffin {l} {T} {0pt} {0pt} } } % set the label box: \hcoffin_set:Nn \l__tasks_label_coffin { \vcoffin_set:Nnn \l__tasks_tmpa_coffin { \dim_abs:n { \l__tasks_label_width_dim } \bool_if:NT \l__tasks_debug_bool {+2\fboxrule } } { \noindent \l__tasks_item_fill_left_tl #1 \l__tasks_item_fill_right_tl \strut } \__tasks_debug:n { \coffin_typeset:Nnnnn \l__tasks_tmpa_coffin {l} {T} {0pt} {0pt} } } % attach the label box at the left of the item box, shifted by % \l__tasks_label_offset_dim : \dim_compare:nNnTF { \l__tasks_label_width_dim } < {0pt} { \coffin_attach:NnnNnnnn \l__tasks_item_coffin {l} {T} \l__tasks_label_coffin {r} {T} { - \l__tasks_label_offset_dim } {0pt} } { \coffin_attach:NnnNnnnn \l__tasks_item_coffin {l} {T} \l__tasks_label_coffin {l} {T} { - \l__tasks_label_offset_dim - \l__tasks_label_width_dim \bool_if:NT \l__tasks_debug_bool {-2\fboxrule } } {0pt} } % when a new row starts enter vertical mode: \int_compare:nNnT { \g__tasks_current_col_num_int } = {1} { \skip_vertical:N \c_zero_skip } % skip horizontally by \l__tasks_item_indent_dim \noindent \skip_horizontal:N \l__tasks_item_indent_dim % typeset the item (with the attached label protruding to the left): \coffin_typeset:Nnnnn \l__tasks_item_coffin {l} {T} {0pt} {0pt} \bool_lazy_or:nnT { \l__tasks_item_full_line_bool } { \bool_lazy_and_p:nn { \l__tasks_item_rest_of_line_bool } { \int_compare_p:nNn { \l__tasks_item_columns_int } = {0} } } { \tasks_new_row: } % are we between items in a row? Then skip by \l__tasks_column_sep_dim : \int_compare:nNnT { \g__tasks_current_col_num_int } < { \l__tasks_columns_int } { \skip_horizontal:N \l__tasks_column_sep_dim } % if we ended a row and a new row is still to come skip vertically by % \l__tasks_after_item_skip : \bool_lazy_and:nnT { \int_compare_p:nNn { \g__tasks_current_col_num_int } = { \l__tasks_columns_int } } { \int_compare_p:n { \g__tasks_current_row_num_int != \g__tasks_rows_int } } { \skip_vertical:N \l__tasks_after_item_skip } % clean up: \coffin_clear:N \l__tasks_item_coffin \coffin_clear:N \l__tasks_label_coffin \coffin_clear:N \l__tasks_tmpa_coffin \bool_set_false:N \l__tasks_item_full_line_bool \bool_set_false:N \l__tasks_item_rest_of_line_bool } \cs_generate_variant:Nn \__tasks_task:nnn {VVV} \cs_new_protected:Npn \__tasks_setup: { \dim_set:Nn \parskip {0pt} % \skip_set:Nn \parfillskip {0pt plus 1fil} % \dim_set_eq:NN \parskip \parsep \dim_set_eq:NN \parindent \listparindent \noindent \strut } \cs_new_protected:Npn \__tasks_gset_rows_num:NN #1#2 { \int_gset:Nn \g__tasks_rows_int { \int_div_truncate:nn {#1} {#2} } \int_compare:nNnT { \int_mod:nn {#1} {#2} } > {0} { \int_gincr:N \g__tasks_rows_int } } \cs_new_protected:Npn \__tasks_label_align:n #1 { \str_case:nnF {#1} { {left} { \tl_clear:N \l__tasks_item_fill_left_tl \tl_set:Nn \l__tasks_item_fill_right_tl {\hfill} } {right} { \tl_set:Nn \l__tasks_item_fill_left_tl {\hfill} \tl_clear:N \l__tasks_item_fill_right_tl } {center} { \tl_set:Nn \l__tasks_item_fill_left_tl {\hfill} \tl_set:Nn \l__tasks_item_fill_right_tl {\hfill} } } { \tl_clear:N \l__tasks_item_fill_left_tl \tl_set:Nn \l__tasks_item_fill_right_tl {\hfill} } } \cs_generate_variant:Nn \__tasks_label_align:n {V} % -------------------------------------------------------------------------- % the `tasks' object: % #1: number of items % #2: number of columns % #3: label-format \DeclareObjectType {tasks} {3} % the `default' template interface: \DeclareTemplateInterface {tasks} {default} {3} { label : tokenlist = \alph*) , ref : tokenlist , indent : length = 2.5em , label-format : tokenlist , label-width : length = 11pt , label-offset : length = .3333em , item-format : tokenlist , after-item-skip : skip = \itemsep } % the `default' template code: \DeclareTemplateCode {tasks} {default} {3} { label = \l__tasks_label_tl , ref = \l__tasks_label_ref_tl , indent = \l__tasks_item_default_indent_dim , label-format = \l__tasks_label_format_tl , label-width = \l__tasks_label_default_width_dim , label-offset = \l__tasks_label_default_offset_dim , item-format = \l__tasks_item_format_tl , after-item-skip = \l__tasks_after_item_skip } { \AssignTemplateKeys \bool_if:NF \l__tasks_label_width_bool { \dim_set_eq:NN \l__tasks_label_width_dim \l__tasks_label_default_width_dim } \bool_if:NF \l__tasks_item_indent_bool { \dim_set_eq:NN \l__tasks_item_indent_dim \l__tasks_item_default_indent_dim } \bool_if:NF \l__tasks_label_offset_bool { \dim_set_eq:NN \l__tasks_label_offset_dim \l__tasks_label_default_offset_dim } \bool_if:NT \l__tasks_custom_after_item_skip_bool { \skip_set_eq:NN \l__tasks_after_item_skip \l__tasks_custom_after_item_skip } \__tasks_label_align:V \l__tasks_label_align_tl % need this for enumerate list: \bool_if:NF \l__tasks_resume_bool { \setcounter { \l__tasks_counter_tl } { \int_eval:n { \l__tasks_start_int -1 } } } \int_set:Nn \l__tasks_columns_int {#2} % set all the items in their own coffins and join with the ground: \int_gzero:N \g__tasks_current_col_num_int \int_gset:Nn \g__tasks_current_row_num_int {1} \tl_if_blank:VF \l__tasks_custom_label_format_tl { \tl_set_eq:NN \l__tasks_label_format_tl \l__tasks_custom_label_format_tl } \tl_if_blank:VF \l__tasks_custom_item_format_tl { \tl_set_eq:NN \l__tasks_item_format_tl \l__tasks_custom_item_format_tl } % prepare counter according to given format: \tl_set:Nx \l__tasks_tmpa_tl { \bool_if:NTF \l__tasks_custom_label_bool { \tl_to_str:V \l__tasks_custom_label_tl } { \tl_to_str:V \l__tasks_label_tl } } \tl_set:Nx \l__tasks_tmpb_tl { \bool_if:NTF \l__tasks_custom_ref_bool { \tl_to_str:V \l__tasks_custom_ref_tl } { \tl_to_str:V \l__tasks_ref_tl } } % replace the stars: \tl_replace_all:Nne \l__tasks_tmpa_tl {*} {{ \l__tasks_counter_tl }} \tl_set_rescan:NnV \l__tasks_tmpa_tl {} \l__tasks_tmpa_tl \tl_if_blank:VTF \l__tasks_tmpb_tl { \tl_set_eq:NN \l__tasks_tmpb_tl \l__tasks_tmpa_tl } { \tl_replace_all:Nne \l__tasks_tmpb_tl {*} {{ \l__tasks_counter_tl }} \tl_set_rescan:NnV \l__tasks_tmpb_tl {} \l__tasks_tmpb_tl } % update \thecounter: \tl_set:cV { the \l__tasks_counter_tl } \l__tasks_tmpb_tl \dim_compare:nNnT { \l__tasks_item_indent_dim } < { \l__tasks_label_offset_dim + \l__tasks_label_width_dim } { \msg_warning:nnnx {tasks} {width-too-small} {item-indent} { \dim_to_decimal:n { \l__tasks_label_offset_dim + \l__tasks_label_width_dim } } } % do the tasks: \seq_map_inline:Nn \l__tasks_seq { \__tasks_read_item:www ##1 \q_stop % TODO \tl_if_eq:NNT \l__tasks_tmp_label_tl \c__tasks_default_label_tl { \refstepcounter { \l__tasks_counter_tl } } \tl_set:Nx \l__tasks_label_tl { { \exp_not:V \l__tasks_tmpa_tl } } \tl_set:cV {tasklabel} \l__tasks_label_tl \bool_if:NTF \l__tasks_custom_label_format_bool { \tl_put_left:NV \l__tasks_label_tl \l__tasks_custom_label_format_tl } { \tl_put_left:NV \l__tasks_label_tl \l__tasks_label_format_tl } % check if the label width is big enough: \bool_set_true:N \l__tasks_measuring_bool \hbox_set:NV \l__tasks_tmpa_box \l__tasks_label_tl \dim_compare:nNnT { \box_wd:N \l__tasks_tmpa_box } > { \l__tasks_label_width_dim } { \msg_warning:nnnx {tasks} {width-too-small} {label-width} { \dim_to_decimal:n { \box_wd:N \l__tasks_tmpa_box } } } \bool_set_false:N \l__tasks_measuring_bool \tl_if_eq:NNTF \l__tasks_tmp_label_tl \c__tasks_default_label_tl { \__tasks_task:VVV \l__tasks_label_tl \l__tasks_item_format_tl \l__tasks_item_tl } { \__tasks_task:VVV \l__tasks_tmp_label_tl \l__tasks_item_format_tl \l__tasks_item_tl \tl_clear:N \l__tasks_tmp_label_tl } } } \cs_new_protected:Npn \__tasks_read_item:www { \peek_charcode_remove:NTF ! { \bool_set_true:N \l__tasks_item_full_line_bool \__tasks_read_item_aux:ww } { \peek_charcode_remove:NTF * { \bool_set_true:N \l__tasks_item_rest_of_line_bool \__tasks_read_item_rest_of_line:ww } { \__tasks_read_item_aux:ww } } } \cs_new_protected:Npn \__tasks_read_item_rest_of_line:ww { \peek_meaning:NTF ( % ) { \__tasks_read_item_rest_of_line_aux:ww } { \__tasks_read_item_rest_of_line_aux:ww (0) } } \cs_new_protected:Npn \__tasks_read_item_rest_of_line_aux:ww (#1) { \int_set:Nn \l__tasks_item_columns_int {#1} \__tasks_read_item_aux:ww } \cs_new_protected:Npn \__tasks_read_item_aux:ww { \peek_meaning:NTF [ % ] { \__tasks_read_item_aux_ii:ww } { \__tasks_read_item_aux_ii:ww [\c__tasks_default_label_tl] } } \cs_new_protected:Npn \__tasks_read_item_aux_ii:ww [#1]#2 \q_stop { \tl_if_eq:nnTF {#1} {\c__tasks_default_label_tl} { \tl_set:NV \l__tasks_tmp_label_tl \c__tasks_default_label_tl } { \tl_set:Nn \l__tasks_tmp_label_tl {{#1}} \tl_put_left:NV \l__tasks_tmp_label_tl \l__tasks_label_format_tl } \tl_set:Nx \l__tasks_item_tl { \tl_trim_spaces:n {#2} } } \__tasks_restore_dollar: % -------------------------------------------------------------------------- \keys_define:nn {tasks/list} { debug .bool_set:N = \l__tasks_debug_bool , break-correction .dim_set:N = \l__tasks_correction_dim , break-correction .initial:n = .00001pt , style .tl_set:N = \l__tasks_instance_tl , style .initial:n = alphabetize , counter-format .code:n = \msg_warning:nnnnn {tasks} {deprecated} {option} {counter-format} {label} \keys_set:nn {tasks/list} { label = #1 } , counter .tl_set:N = \l__tasks_counter_tl , counter .initial:n = task , label .code:n = \bool_set_true:N \l__tasks_custom_label_bool \tl_set:Nn \l__tasks_custom_label_tl {#1} , ref .code:n = \bool_set_true:N \l__tasks_custom_ref_bool \tl_set:Nn \l__tasks_custom_ref_tl {#1} , label-format .code:n = \bool_set_true:N \l__tasks_custom_label_format_bool \tl_set:Nn \l__tasks_custom_label_format_tl {#1} , label-width .code:n = \dim_set:Nn \l__tasks_label_width_dim {#1} \bool_set_true:N \l__tasks_label_width_bool , label-offset .code:n = \dim_set:Nn \l__tasks_label_offset_dim {#1} \bool_set_true:N \l__tasks_label_offset_bool , label-align .tl_set:N = \l__tasks_label_align_tl , item-format .tl_set:N = \l__tasks_custom_item_format_tl , item-indent .code:n = \dim_set:Nn \l__tasks_item_indent_dim {#1} \bool_set_true:N \l__tasks_item_indent_bool , column-sep .dim_set:N = \l__tasks_column_sep_dim , before-skip .skip_set:N = \l__tasks_before_list_skip , before-skip .initial:n = \topsep , after-skip .skip_set:N = \l__tasks_after_list_skip , after-skip .initial:n = \topsep , after-item-skip .code:n = \bool_set_true:N \l__tasks_custom_after_item_skip_bool \skip_set:Nn \l__tasks_custom_after_item_skip {#1} , after-item-skip .initial:n = \itemsep , resume .bool_set:N = \l__tasks_resume_bool , start .int_set:N = \l__tasks_start_int , start .initial:n = 1 } % -------------------------------------------------------------------------- % #1: item separator % #2: options % #3: number of columns % #4: environment body \cs_new_protected:Npn \tasks_body:nnnn #1#2#3#4 { \int_gincr:N \g__tasks_env_int \legacy_if:nT {@inlabel} { \noindent\par \nobreak \vskip-\parskip \vskip-\baselineskip \hrule\@height\z@ } \keys_set:nn {tasks/list} {#2} \dim_compare:nNnF { \l__tasks_before_list_skip } = {0pt} { \par\addvspace {\l__tasks_before_list_skip} } \list {} { \dim_set:Nn \leftmargin {0pt} \dim_set:Nn \rightmargin {0pt} \dim_set:Nn \parsep {0pt} \dim_set:Nn \partopsep {0pt} \dim_set:Nn \topsep {0pt} \dim_set:Nn \itemsep {0pt} } \item \scan_stop: \dim_set:Nn \l__tasks_full_width_dim { \linewidth } \tasks_environment:Vnnn \l__tasks_instance_tl {#3} {#1} {#4} \endlist \dim_compare:nNnF { \l__tasks_after_list_skip } = {0pt} { \addvspace {\l__tasks_after_list_skip} } } % -------------------------------------------------------------------------- % command to start a new row: \cs_new_protected:Npn \tasks_new_row: { \int_gset:Nn \g__tasks_total_items_int { \g__tasks_total_items_int + \l__tasks_columns_int - \g__tasks_current_col_num_int } \__tasks_gset_rows_num:NN \g__tasks_total_items_int \l__tasks_columns_int \int_gset_eq:NN \g__tasks_current_col_num_int \l__tasks_columns_int } \NewDocumentCommand \startnewitemline {} { \tasks_new_row: } % -------------------------------------------------------------------------- % the user environment: \NewDocumentCommand \NewTasksEnvironment { O{}mO{\task}D(){1} } { \NewDocumentEnvironment {#2} { O{}D(){#4}+b } { \tasks_body:nnnn {#3} {#1,##1} {##2} {##3} } { } } \NewDocumentCommand \RenewTasksEnvironment { O{}mO{\task}D(){1} } { \RenewDocumentEnvironment {#2} { O{}D(){#4}+b } { \tasks_body:nnnn {#3} {#1,##1} {##2} {##3} } { } } \tasks_deprecated:NN \NewTasks \NewTasksEnvironment \tasks_deprecated:NN \RenewTasks \RenewTasksEnvironment % -------------------------------------------------------------------------- % default list: \NewTasksEnvironment {tasks} % base instance: % ALPHABETIZE: a) b) c) \DeclareInstance {tasks} {alphabetize} {default} { } % ITEMIZE: \DeclareInstance {tasks} {itemize} {default} { label-width = 1.125em , label = \labelitemi } % ENUMERATE: \DeclareInstance {tasks} {enumerate} {default} { label = \arabic*. } % -------------------------------------------------------------------------- % setup: \cs_new_protected:Npn \tasks_setup:n #1 { \keys_set:nn {tasks/list} {#1} } \NewDocumentCommand \settasks { +m } { \tasks_setup:n {#1} } % default: \__tasks_label_align:n {left} % -------------------------------------------------------------------------- \file_if_exist:nT {tasks.cfg} { \file_input:n {tasks.cfg} } \AtBeginDocument { \@ifpackageloaded {hyperref} { \tl_set:Nn \theHtask { \int_use:N \g__tasks_env_int . \arabic { \l__tasks_counter_tl } } } {} } \file_input_stop: % -------------------------------------------------------------------------- % HISTORY: 2013/01/19 v0.7 - extracted from `exsheets' package; this also lead to a slightly new syntax and a few new options for it 2013/04/04 v0.8a - corrected \seq_length:N => \seq_count:N 2013/04/07 v0.9 - protected internal commands where appropriate - made enumerated item referenceable with \label{} and \ref{}; this introduced new options: * the former `label-format' is now `counter-format' * new: `label-format' - changed defaults for `label-width' and `label-offset' - ensure that the `after-item-skip' is only inserted in between rows - new option `after-item-skip' - improvements when label are set with optional argument: * a provided but empty argument is now correctly recognized * the counter is _not_ stepped anymore for enumerated lists when the optional argument is provided - new command \startnewitemline that forces the next item to be put at the beginning of a row 2013/04/22 v0.9a - new option `item-indent' - synchronized version number with `exsheets' until now but won't any more 2013/12/03 v0.9b - add missing \noindent for the case when \listparindent is non-zero, fixes http://tex.stackexchange.com/q/148082/5049 2014/05/11 v0.9c - remove definition of the \task macro: it is not necessary for `tasks' to function but it conflicts e.g. with `ltxdoc' class 2014/07/20 v0.10 - new option `debug' - new option `column-sep - renamed a few internal variables - remove package from the `exsheets' bundle and distribute it as package of its own - new: optional bang to a \task forces an item to use a full line (\task!) - new: optional star to a \task forces an item to use the complete remaining line (\task*); the star has itself has an optional argument for specifying the number of columns to span (\task*()) 2014/07/29 v0.10a - bug-fix: correct typo in option definition of `column-sep' - insert before/after skip with \vspace* - remove unnecessary (and unused) arguments of \__tasks_task:nn - add \strut to the end of an item 2016/05/03 v0.11 - new option: `item-format' - some changes to how the list is displayed, especially regarding spacing -- it now better resembles the standard lists 2016/05/04 v0.11a - enable `style' option globally again 2016/08/13 v0.12 - the item indent and label width and label offset now play together like one would expect: an item indent of 0pt will align the complete item with the margin and the needed overlap for the label is reserved 2016/08/16 v0.13 - a negative value for label width will make the label protrude to the margin 2019/10/04 v1.0 - get rid of `cntformats', `environ' and `epic' - no default multiple choice any more - rename \NewTasks and \RenewTasks - the option `counter-format' is deprecated 2019/10/05 v1.0a - fix small bug in deprecation message 2019/10/06 v1.0b - fix bug in `label-format' definition 2019/10/07 v1.0c - fix bug in width warning - fix bug in deprecation of `counter-format' 2019/10/08 v1.0d - make \thetask usable; and correct \label/\ref 2019/11/03 v1.1 - fix typo - make \settasks' argument long - new option `start' 2020/01/11 v1.1a - allow `label-format' to end with command that needs an argument 2020/03/21 v1.2 - prefer lazy boolean evaluation - \tasksifmeasuringTF - new option `counter' - rename manual files 2020/04/19 v1.2a - only use arabic numbers for \theHtask 2020/05/11 v1.2b - options are set to late for `before-skip' -- fixed 2020/08/19 v1.3 - add `ref' option 2021/02/20 v1.3a - fix issue #23 2022/01/08 v1.4 - fix issue #27 2022/01/08 v1.4a - change \vspace into \addvspace so that consecutive lists don't add their vertical seps, see https://tex.stackexchange.com/q/222973/