%% %% This is file `multicolrule.sty', %% generated with the docstrip utility. %% %% The original source files were: %% %% multicolrule.dtx (with options: `package') %% ---------------------------------------------------------------- %% multicolrule --- Decorative rules between columns %% Author: Karl Hagen %% Email: latex@polysyllabic.com %% Released under the LaTeX Project Public License v1.3c or later %% See http://www.latex-project.org/lppl.txt %% ---------------------------------------------------------------- %% \RequirePackage{expl3} \RequirePackage{xparse} \ProvidesExplPackage {multicolrule} {2020/09/14} {1.3a} {Decorative vertical rules between columns} \RequirePackage{l3keys2e} \RequirePackage{xpatch} \RequirePackage{xcolor} \RequirePackage{scrlfile} \msg_new:nnn {multicolrule} {patch-success} {Patched~#1.} \msg_new:nnn {multicolrule} {patch-failure} {Error~patching~#1.} \msg_new:nnnn {multicolrule} {tikz-required} {Tikz~required} {The~'#1'~setting~requires~tikz~to~work.~Either~load~tikz~before~you~load~ multicolrule~or~use~multicolrule's~'tikz'~package~option.} \msg_new:nnnn {multicolrule} {multicol-loaded} {Multicol~loaded} {You~are~ using~the~'twocolumn'~option~with~multicol~already~loaded.~You~will~likely~ run~into~problems.} \msg_new:nnnn {multicolrule} {pattern-undefined} {Pattern~undefined} {The~multicolrule~pattern~'#1'~has~not~been~defined.} \bool_new:N \g__mcrule_twocolumn_bool \bool_new:N \g__mcrule_use_tikz_bool \bool_new:N \g__mcrule_paracol_bool \int_new:N \l__mcrule_repeat_int \int_set:Nn \l__mcrule_repeat_int {1} \dim_new:N \l__mcrule_repeat_distance_dim \dim_new:N \l__mcrule_extend_top_dim \dim_new:N \l__mcrule_extend_bot_dim \bool_new:N \l__mcrule_extend_fill_bool \dim_new:N \l__mcrule_extend_reserve_dim \tl_new:N \l__mcrule_color_name_tl \tl_new:N \l__mcrule_color_model_tl \prop_new:N \g__mcrule_patterns_prop \int_new:N \g__mcrule_pattern_count_int \int_new:N \g__mcrule_pattern_for_int \int_new:N \g__mcrule_pattern_after_int \seq_new:N \l__mcrule_pattern_list_seq \@ifpackageloaded{tikz} { \bool_gset_true:N \g__mcrule_use_tikz_bool }{} \keys_define:nn {mcrule-opts} { twocolumn .bool_gset:N = \g__mcrule_twocolumn_bool, twocolumn .default:n = true, tikz .bool_gset:N = \g__mcrule_use_tikz_bool, tikz .default:n = true, paracol .bool_gset:N = \g__mcrule_paracol_bool, paracol .default:n = true, } \ProcessKeysOptions{mcrule-opts} \cs_new:Npn \__mcrule_column_height: {} \cs_new:Npn \__mcrule_column_depth: {} \cs_new:Npn \__mcrule_column_overflow: {0pt} \cs_new_protected:Npn \__mcrule_patch_mcol_output:N #1 { \xpatchcmd{#1} {\columnseprulecolor\vrule\@width\columnseprule} {\mcruledivider} {\msg_info:nnn {multicolrule} {patch-success} {#1}} {\msg_info:nnn {multicolrule} {patch-failure} {#1}} } \cs_new_protected:Npn \__mcrule_patch_twocol_output:N #1 { \xpatchcmd{#1} {\normalcolor\vrule\@width\columnseprule} {\mcruledivider} {\msg_info:nnn {multicolrule} {patch-success} {#1}} {\msg_info:nnn {multicolrule} {patch-failure} {#1}} } \bool_if:NTF \g__mcrule_twocolumn_bool { \@ifpackageloaded{multicol} {\msg_warning:nn {multicolrule} {multicol-loaded}}{} \cs_gset:Npn \columnseprulecolor {\normalcolor} \cs_gset:Npn \__mcrule_column_height: {\box_ht:N \@outputbox} \cs_gset:Npn \__mcrule_column_depth: {\box_dp:N \@outputbox} \__mcrule_patch_twocol_output:N \@outputdblcol \AfterAtEndOfPackage*{bidi} { \__mcrule_patch_twocol_output:N \RTL@outputdblcol \__mcrule_patch_twocol_output:N \LTR@outputdblcol } } { \RequirePackage{multicol} \__mcrule_patch_mcol_output:N \LR@column@boxes \__mcrule_patch_mcol_output:N \RL@column@boxes \cs_gset:Npn \__mcrule_column_height: { \box_ht:N \mult@rightbox } \cs_gset:Npn \__mcrule_column_depth: { \dim_max:nn {\dimen\tw@}{\box_dp:N \mult@rightbox} } \cs_gset:Npn \__mcrule_column_overflow: { \dim_max:nn {\box_ht:N \mult@nat@firstbox - \box_ht:N \mult@rightbox}{0pt} } \LRmulticolcolumns \AfterPackage!{bidi} { \cs_gset_eq:NN \LTR@column@boxes \LR@column@boxes \cs_gset_eq:NN \RTL@column@boxes \RL@column@boxes \cs_gset_eq:NN \LRmulticolcolumns \LTRmulticolcolumns \cs_gset_eq:NN \RLmulticolcolumns \RTLmulticolcolumns } } \cs_new_protected:Npn \mcruledivider { \int_compare:nNnTF {\g__mcrule_pattern_after_int} > {\c_zero_int} { \int_gdecr:N \g__mcrule_pattern_after_int } { \bool_lazy_and:nnT {\int_compare_p:nNn {\seq_count:N \l__mcrule_pattern_list_seq} > {\c_zero_int}} {! \int_compare_p:nNn {\g__mcrule_pattern_for_int} = {\c_zero_int}} { \int_gincr:N \g__mcrule_pattern_count_int \int_compare:nNnT {\g__mcrule_pattern_count_int} > {\seq_count:N \l__mcrule_pattern_list_seq} { \int_gset:Nn \g__mcrule_pattern_count_int {\c_one_int} } \tl_set:Nx \l_tmpa_tl {\seq_item:Nn \l__mcrule_pattern_list_seq {\g__mcrule_pattern_count_int} } \tl_if_blank:VF \l_tmpa_tl { \__mcrule_set_pattern:V \l_tmpa_tl } \int_compare:nNnT {\g__mcrule_pattern_for_int} > {\c_zero_int} { \int_gdecr:N \g__mcrule_pattern_for_int } } } \columnseprulecolor \bool_lazy_and:nnT {\dim_compare_p:nNn {\columnseprule} > {\c_zero_dim}} {\int_compare_p:nNn {\l__mcrule_repeat_int} > {\c_zero_int}} { \mcrule_divider: \prg_replicate:nn {\l__mcrule_repeat_int - \c_one_int} { \hspace{\l__mcrule_repeat_distance_dim} \mcrule_divider: } } } \cs_new:Npn \__mcrule_column_total_height: { \dim_eval:n {\__mcrule_column_height: + \__mcrule_column_depth: + \__mcrule_extend_column_top: + \__mcrule_column_overflow: + \__mcrule_extend_column_bottom:} } \cs_new:Npn \__mcrule_column_total_depth: { \dim_eval:n {\__mcrule_column_depth: + \__mcrule_column_overflow: + \__mcrule_extend_column_bottom:} } \cs_new:Npn \__mcrule_extend_column_top: { \l__mcrule_extend_top_dim } \cs_new:Npn \__mcrule_extend_column_bottom: { \bool_lazy_and:nnTF {\bool_if_p:n {\l__mcrule_extend_fill_bool}} {\bool_not_p:n {\g__mcrule_twocolumn_bool}} { \dim_compare:nNnTF {\@colroom - \__mcrule_column_height: - \__mcrule_extend_reserve:} > {\c_zero_dim} {\@colroom - \__mcrule_column_height: - \__mcrule_extend_reserve:} {\c_zero_dim} } {\l__mcrule_extend_bot_dim} } \cs_new:Npn \__mcrule_extend_reserve: { \dim_compare:nNnTF {\l__mcrule_extend_reserve_dim} > {\c_zero_dim} {\dim_eval:n {\l__mcrule_extend_reserve_dim + \multicolsep}} {\c_zero_dim} } \cs_new:Npn \mcrule_divider: {\vrule\@width\columnseprule} \cs_new_nopar:Npn \__mcrule_pattern:nnn #1#2#3 { \box_move_down:nn {\__mcrule_column_total_depth:} { \vbox_to_ht:nn {\__mcrule_column_total_height:} { \tex_vfill:D \tex_kern:D \dim_eval:n {#2} \exp_stop_f: \hbox:n{#1} \tex_kern:D \dim_eval:n {#3} \exp_stop_f: \tex_vfill:D } } } \cs_new_nopar:Npn \__mcrule_tile_pattern:nnn #1#2#3 { \box_move_down:nn {\__mcrule_column_total_depth:} { \vbox_to_ht:nn {\__mcrule_column_total_height:} { \tex_cleaders:D \vbox:n { \tex_kern:D \dim_eval:n {#2} \exp_stop_f: \hbox:n{#1} \tex_kern:D \dim_eval:n {#3} \exp_stop_f: } \tex_vfill:D } } } \cs_new:Npn \__mcrule_line_pattern:nnnn #1#2#3#4 { \bool_if:NTF \g__mcrule_use_tikz_bool { \__mcrule_pattern_line:n {#1} } { \__mcrule_tile_pattern:nnn {\rule{\columnseprule}{#2}}{#3}{#4} } } \cs_new:Npn \__mcrule_solid_line: { \rule[-\__mcrule_column_total_depth:]{\columnseprule}{\__mcrule_column_total_height:} } \cs_new:Npn \__mcrule_strut: { \rule[-\__mcrule_column_total_depth:]{0pt}{\__mcrule_column_total_height:} } \bool_if:NTF \g__mcrule_use_tikz_bool { \ExplSyntaxOff \RequirePackage{tikz} \ExplSyntaxOn \cs_set:Npn \__mcrule_tikz_picture:n #1 { \begin{tikzpicture}[x=1pt,y=1pt,inner~sep=0pt,outer~sep=0pt, baseline={([yshift=\__mcrule_column_total_depth:]current~bounding~box.south)}] \node (TOP) at (0,\__mcrule_column_total_height:) {}; \node (BOT) at (0,0) {}; #1 \end{tikzpicture} } \cs_set:Npn \__mcrule_pattern_line:n #1 { \begin{tikzpicture}[x=1pt,y=1pt,inner~sep=0pt,outer~sep=0pt, baseline={([yshift=\__mcrule_column_total_depth:]current~bounding~box.south)}] \draw[line~width=\columnseprule,#1] (0,\__mcrule_column_total_height:) -- (0,0); \end{tikzpicture} } \cs_set:Npn \__mcrule_circle: { \begin{tikzpicture}[x=1pt,y=1pt,inner~sep=0pt,outer~sep=0pt] \draw (0,0) circle[radius=.5\columnseprule]; \end{tikzpicture} } \cs_set:Npn \__mcrule_solid_circle: { \begin{tikzpicture}[x=1pt,y=1pt,inner~sep=0pt,outer~sep=0pt] \fill (0,0) circle[radius=.5\columnseprule]; \end{tikzpicture} } } { \cs_set:Npn \__mcrule_tikz_picture:n #1 {\msg_error:nnn {multicolrule} {tikz-required} {#1}} \cs_new:Npn \__mcrule_pattern_line:n #1 {\msg_error:nnn {multicolrule} {tikz-required} {#1}} \cs_new:Npn \__mcrule_circle: {\msg_error:nnn {multicolrule} {tikz-required} {circles}} \cs_new:Npn \__mcrule_solid_circle: {\msg_error:nnn {multicolrule} {tikz-required} {solid-circles}} } \cs_new_protected:Npn \__mcrule_set_rule_color: { \tl_if_empty:NT \l__mcrule_color_name_tl { \tl_set:Nn \l__mcrule_color_name_tl {black} } \tl_if_empty:NTF \l__mcrule_color_model_tl { \cs_set:Npn \columnseprulecolor {\color{\l__mcrule_color_name_tl}} } { \cs_set:Npn \columnseprulecolor {\color[\l__mcrule_color_model_tl]{\l__mcrule_color_name_tl}} } } \cs_new_protected:Npn \__mcrule_set_pattern_list:n #1 { \seq_set_split:Nnn \l__mcrule_pattern_list_seq {,} {#1} \int_gzero:N \g__mcrule_pattern_count_int \int_gzero:N \g__mcrule_pattern_after_int \int_gset:Nn \g__mcrule_pattern_for_int {-1} } \cs_new_protected:Npn \__mcrule_set_pattern:n #1 { \prop_get:NnNTF \g__mcrule_patterns_prop {#1} \l_tmpa_tl { \keys_set_filter:nnV {mcrule} {patterns} \l_tmpa_tl } { \msg_error:nnn {multicolrule} {pattern-undefined} {#1} } \tl_set:Nn \l_tmpa_tl {\prop_item:Nn \g__mcrule_patterns_prop {#1}} } \cs_generate_variant:Nn \__mcrule_set_pattern:n {V} \keys_define:nn {mcrule} { extend-top .dim_set:N = \l__mcrule_extend_top_dim, extend-bot .dim_set:N = \l__mcrule_extend_bot_dim, extend-fill .bool_set:N = \l__mcrule_extend_fill_bool, extend-fill .default:n = true, extend-reserve .dim_set:N = \l__mcrule_extend_reserve_dim, expand .code:n = { \dim_set:Nn \l__mcrule_extend_bot_dim {#1} \dim_set:Nn \l__mcrule_extend_top_dim {#1} }, shift .code:n = { \dim_set:Nn \l__mcrule_extend_bot_dim {#1} \dim_set:Nn \l__mcrule_extend_top_dim {\fp_to_dim:n {-1 * \l__mcrule_extend_bot_dim}} }, line-style .choice:, line-style / default .code:n = \cs_set:Npn \mcrule_divider: {\vrule\@width\columnseprule}, line-style / solid .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_solid_line:}, line-style / strut .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_strut:}, line-style / dots .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_tile_pattern:nnn {.}{1pt}{1pt}}, line-style / dense-dots .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_tile_pattern:nnn {.}{1pt}{0pt}}, line-style / loose-dots .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_tile_pattern:nnn {.}{2pt}{2pt}}, line-style / circles .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_tile_pattern:nnn {\__mcrule_circle:}{1pt}{1pt}}, line-style / dense-circles .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_tile_pattern:nnn {\__mcrule_circle:}{1pt}{0pt}}, line-style / loose-circles .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_tile_pattern:nnn {\__mcrule_circle:}{2pt}{2pt}}, line-style / solid-circles .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_tile_pattern:nnn {\__mcrule_solid_circle:}{1pt}{1pt}}, line-style / dense-solid-circles .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_tile_pattern:nnn {\__mcrule_solid_circle:}{1pt}{0pt}}, line-style / loose-solid-circles .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_tile_pattern:nnn {\__mcrule_solid_circle:}{2pt}{2pt}}, line-style / dotted .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_line_pattern:nnnn {dotted}{\columnseprule}{1pt}{1pt}}, line-style / densely-dotted .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_line_pattern:nnnn {densely~dotted}{\columnseprule}{1pt}{0pt}}, line-style / loosely-dotted .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_line_pattern:nnnn {loosely~dotted}{\columnseprule}{2pt}{2pt}}, line-style / dashed .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_line_pattern:nnnn {dashed}{3pt}{1.5pt}{1.5pt}}, line-style / densely-dashed .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_line_pattern:nnnn {densely~dashed}{3pt}{1pt}{1pt}}, line-style / loosely-dashed .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_line_pattern:nnnn {loosely~dashed}{3pt}{3pt}{3pt}}, line-style / dash-dot .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_pattern_line:n{dash~dot}}, line-style / densely-dash-dot .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_pattern_line:n{densely~dash~dot}}, line-style / loosely-dash-dot .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_pattern_line:n{loosely~dash~dot}}, line-style / dash-dot-dot .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_pattern_line:n{dash~dot~dot}}, line-style / densely-dash-dot-dot .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_pattern_line:n{densely~dash~dot~dot}}, line-style / loosely-dash-dot-dot .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_pattern_line:n{loosely~dash~dot~dot}}, color .code:n = { \tl_set:Nn \l__mcrule_color_name_tl {#1} \__mcrule_set_rule_color: }, color-model .code:n = { \tl_set:Nn \l__mcrule_color_model_tl {#1} \__mcrule_set_rule_color: }, custom-line .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_tikz_picture:n {#1}}, custom-pattern .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_pattern:nnn #1}, custom-tile .code:n = \cs_set:Npn \mcrule_divider: {\__mcrule_tile_pattern:nnn #1}, width .choice:, width / ultra-thin .code:n = \dim_set:Nn \columnseprule {0.1pt}, width / very-thin .code:n = \dim_set:Nn \columnseprule {0.2pt}, width / thin .code:n = \dim_set:Nn \columnseprule {0.4pt}, width / semithick .code:n = \dim_set:Nn \columnseprule {0.6pt}, width / thick .code:n = \dim_set:Nn \columnseprule {0.8pt}, width / very-thick .code:n = \dim_set:Nn \columnseprule {1.2pt}, width / ultra-thick .code:n = \dim_set:Nn \columnseprule {1.6pt}, width / unknown .code:n = \dim_set:Nn \columnseprule {#1}, repeat .int_set:N = \l__mcrule_repeat_int, repeat-distance .dim_set:N = \l__mcrule_repeat_distance_dim, single .meta:n = { repeat = 1, repeat-distance = #1 }, single .default:n = \columnseprule, double .meta:n = { repeat = 2, repeat-distance = #1 }, double .default:n = \columnseprule, triple .meta:n = { repeat = 3, repeat-distance = #1 }, triple .default:n = \columnseprule, patterns .code:n = \__mcrule_set_pattern_list:n {#1}, patterns .groups:n = {patterns}, pattern-after .int_gset:N = \g__mcrule_pattern_after_int, pattern-for .int_gset:N = \g__mcrule_pattern_for_int, } \NewDocumentCommand{\SetMCRule}{m} { \keys_set:nn {mcrule} {#1} } \NewDocumentCommand{\DeclareMCRulePattern}{m m} { \prop_gput:Nnn \g__mcrule_patterns_prop {#1} {#2} } %% Copyright (C) 2018-2020 by Karl Hagen %% %% This file may be distributed and/or modified under the %% conditions of the LaTeX Project Public License (LPPL), either %% version 1.3c of this license or (at your option) any later %% version. The latest version of this license is in the file: %% https://www.latex-project.org/lppl.txt %% %% This work is "maintained" (as per LPPL maintenance status) by %% Karl Hagen. %% %% This work consists of the files multicolrule.dtx and %% mcrule-examples.tex, %% and the derived files multicolrule.ins, %% multicolrule.sty, %% multicolrule.pdf, and %% mcrule-examples.pdf. %% %% End of file `multicolrule.sty'.