From b65568f44e519d69d9eb8789f1b40981f4b55759 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Sun, 25 Oct 2020 21:34:16 +0000 Subject: association-matrix (25oct20) git-svn-id: svn://tug.org/texlive/trunk@56759 c570f23f-e606-0410-a88d-b1316a301751 --- .../association-matrix/association-matrix.sty | 373 +++++++++++++++++++++ 1 file changed, 373 insertions(+) create mode 100644 Master/texmf-dist/tex/latex/association-matrix/association-matrix.sty (limited to 'Master/texmf-dist/tex/latex/association-matrix') diff --git a/Master/texmf-dist/tex/latex/association-matrix/association-matrix.sty b/Master/texmf-dist/tex/latex/association-matrix/association-matrix.sty new file mode 100644 index 00000000000..07b73659b63 --- /dev/null +++ b/Master/texmf-dist/tex/latex/association-matrix/association-matrix.sty @@ -0,0 +1,373 @@ +%% association-matrix.sty +%% Copyright 2020 Whisperity +% +% 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 Whisperity. +% +% This work consists of the files association-matrix.sty +% and association-matrix.tex. +% +\NeedsTeXFormat{LaTeX2e}[2017/01/01] +\ProvidesPackage{association-matrix}[2020/10/25 v1.0 Association matrix generator] + +\RequirePackage{etoolbox} +\RequirePackage{forloop} +\RequirePackage{ifthen} +\RequirePackage{textcomp} +\RequirePackage{xparse} + +\newrobustcmd{\amxDate}{2020/10/25} +\newrobustcmd{\amxVersion}{1.0} + +\ExplSyntaxOn +% (via http://tex.stackexchange.com/a/300215) +\NewExpandableDocumentCommand{\egreg@Repeat}{O{}mm} + { + \int_compare:nT { #2 > 0 } + { + #3 \prg_replicate:nn { #2 - 1 } { #1#3 } + } + } +\ExplSyntaxOff + +%%% +%%% FIELDS, REPRESENTATION AND DEFINITION FUNCTIONS +%%% + +%% Internal cursors that are used for various iteration purposes. +\newcounter{amx@CursorR} +\newcounter{amx@CursorC} +\newcounter{amx@Cursor} + +%% Internal data structure holding the row keys. +\newcommand{\amx@Rows}{} +%% The total number of theses defined. +\newcounter{amx@RowCount} +%% +%% Internal data structure holding the column keys. +\newcommand{\amx@Cols}{} +%% The total number of columns defined. +\newcounter{amx@ColumnCount} +%% +%% Internal data structure holding the row-to-column assignments. +\newcommand{\amx@Associations}{} +%% +%% Returns the number of theses that are defined. +\newrobustcmd{\amxrows}{\the\value{amx@RowCount}} +%% Returns the number of columns that are defined. +\newrobustcmd{\amxcols}{\the\value{amx@ColumnCount}} +%% +%% Retrieve the name for the th row. +\newcommand{\amx@RowKey}[1]{\csname amx@Rows@#1\endcsname} +%% Retrieve the text for the th row. +\newcommand{\amx@RowText}[1]{\csname amx@RowTexts@#1\endcsname} +%% Retrieve the name for the th column. +\newcommand{\amx@ColumnKey}[1]{\csname amx@Cols@#1\endcsname} +%% Retrieve the text for the th column. +\newcommand{\amx@ColumnText}[1]{\csname amx@ColTexts@#1\endcsname} +%% + +%% Registers the row with the given key, and text. +\newrobustcmd{\amx@NewRow}[2]{% + \stepcounter{amx@RowCount}% + % + \listcsgadd{amx@Rows}{#1}% + \expandafter\def\csname amx@Rows@\theamx@RowCount\endcsname{#1}% + \expandafter\def\csname amx@RowTexts@\theamx@RowCount\endcsname{#2}% +} +%% \amxrow{}{} +%% registers the row of to be +\newrobustcmd{\amxrow}[2]{% + \amx@NewRow{#1}{#2}% +} + +%% Retrieve the text for the row defined as . +\newrobustcmd{\amxrowtext}[1]{% + \amx@FindRowIndex{#1}% + \amx@RowText{\theamx@CursorR}% +} + +%% Registers the public with the given key, and body. +\newrobustcmd{\amx@NewColumn}[2]{% + \stepcounter{amx@ColumnCount}% + % + \listcsgadd{amx@Cols}{#1}% + \expandafter\def\csname amx@Cols@\theamx@ColumnCount\endcsname{#1}% + \expandafter\def\csname amx@ColTexts@\theamx@ColumnCount\endcsname{#2}% +} +%% \amxcol{}{} +%% registers the column of to be +\newrobustcmd{\amxcol}[2]{% + \amx@NewColumn{#1}{#2}% +} + +%% Retrieve the text for the column defined as . +\newrobustcmd{\amxcoltext}[1]{% + \amx@FindColumnIndex{#1}% + \amx@ColumnText{\theamx@CursorC}% +} + +%% Sets that #1 col is related to #2 row (both args are keys). +\newrobustcmd{\amx@AssociateRowToCol}[2]{% + \amx@FindRowIndex{#1} % CursorR set. + \amx@FindColumnIndex{#2} % CursorC set. + % Format is: (row,column) pairs in the list. + \listcsxadd{amx@Associations}{(\amx@RowKey{\theamx@CursorR},\amx@ColumnKey{\theamx@CursorC})}% +} +%% \amxassociate +%% assigns the given column to be relevant for the given row. +\newrobustcmd{\amxassociate}[2]{% + \amx@AssociateRowToCol{#2}{#1}% +} + +%% +%% ALGORITHMS & ITERATORS +%% + +%% Internal command which sets the counter amx@CursorR to the index of the row with the given . +\newcommand\amx@FindRowIndex[1]{% + \renewcommand*{\do}[1]{% + \ifstrequal{##1}{#1}% + {\listbreak}% + {\stepcounter{amx@CursorR}}% + }% + \setcounter{amx@CursorR}{0}% + \dolistcsloop{amx@Rows}% + \stepcounter{amx@CursorR}% + % + \ifnumgreater{\value{amx@CursorR}}{\value{amx@RowCount}}{% + \PackageError{association-matrix}{Requested information about row '#1' but it doesn't exist}{% + Check that functions such as \detokenize{\amxrowtext} are not given undefined row keys!}% + }% +} + +%% Internal command which sets the counter amx@CursorC to the index of the +%% column with the given . +\newcommand\amx@FindColumnIndex[1]{% + \renewcommand*{\do}[1]{% + \ifstrequal{##1}{#1}% + {\listbreak}% + {\stepcounter{amx@CursorC}}% + }% + \setcounter{amx@CursorC}{0}% + \dolistcsloop{amx@Cols}% + \stepcounter{amx@CursorC}% + % + \ifnumgreater{\value{amx@CursorC}}{\value{amx@ColumnCount}}{% + \PackageError{association-matrix}{Requested information about column '#1' but it doesn't exist}{% + Check that functions such as \detokenize{\amxcoltext} are not given undefined column keys!}% + }% +} + +%% amx@RowColAssigned {} {} {} {} +%% If the column given is assigned by the client to the row given, executes , otherwise, . +\newcommand{\amx@RowColAssigned}[4]{% + \xifinlistcs{(#1,#2)}{amx@Associations}{#3}{#4}% +} + +%% +%% RENDERERS AND FORMAT CUSTOMISATION +%% + +%% Renderer for the table's 1st cell. +\newcommand{\amx@Renderer@Default@TopCorner}{Associations} +\newcommand{\amx@Renderer@TopCorner}{} % Dummy. +\newrobustcmd{\amxsetTopCorner}[1]{% + \renewcommand{\amx@Renderer@TopCorner}{#1}% +} +%% +%% Renderer for the title text entries in the rows. +\newcommand{\amx@Renderer@Default@Row}[2]{% + #1. #2% +} +\newcommand{\amx@Renderer@Default@Row@Highlighted}[2]{% + #1. \textbf{#2}% +} +\newcommand{\amx@Renderer@Row}{} % Dummy. +\newcommand{\amx@Renderer@Row@Highlighted}{} % Dummy. +\newrobustcmd{\amxsetRowFormat}[1]{% + \renewcommand{\amx@Renderer@Row}{#1}% +} +\newrobustcmd{\amxsetRowFormatHighlighted}[1]{% + \renewcommand{\amx@Renderer@Row@Highlighted}{#1}% +} +%% +%% Renderer for the columns' first cells. +\newcommand{\amx@Renderer@Default@ColumnHeading}[1]{#1} +\newcommand{\amx@Renderer@ColumnHeading}{} % Dummy. +\newrobustcmd{\amxsetColumnHeading}[1]{% + \renewcommand{\amx@Renderer@ColumnHeading}{#1}% +} +%% +%% Renderer for the indicators in the rows. +\newcommand{\amx@Renderer@Default@Indicator}{% + \textbullet% +} +\newcommand{\amx@Renderer@Default@Indicator@Highlighted@Current}{% + \textbullet% +} +\newcommand{\amx@Renderer@Default@Indicator@Highlighted@Other}{% + \textopenbullet% +} +\newcommand{\amx@Renderer@Indicator}{} % Dummy. +\newcommand{\amx@Renderer@Indicator@Highlighted@Current}{} % Dummy. +\newcommand{\amx@Renderer@Indicator@Highlighted@Other}{} % Dummy. +\newrobustcmd{\amxsetIndicator}[1]{% + \renewcommand{\amx@Renderer@Indicator}{#1}% +} +\newrobustcmd{\amxsetIndicatorHighlighted}[2]{% + \renewcommand{\amx@Renderer@Indicator@Highlighted@Current}{#1}% + \renewcommand{\amx@Renderer@Indicator@Highlighted@Other}{#2}% +} + +%% +%% RENDERING +%% + +%% Internal toggle that specifies whether the current row of \RowsVSCols +%% should be highlighted or not. +\newtoggle{amx@AreAnyHighlightSet} +\newtoggle{amx@IsCurrentRowHighlighted} +% +\newcommand{\amx@amx@RowRenderHELPER}[1]{} % Dummy. + +%% Renders the heading of the table. +\newcommand{\amx@amx@RenderHeading}{% + \setcounter{amx@CursorC}{\value{amx@ColumnCount}}% + \stepcounter{amx@CursorC}% + % + \amx@Renderer@TopCorner{}% + \forloop{amx@Cursor}{1}{\value{amx@Cursor} < \value{amx@CursorC}}{% + & \amx@Renderer@ColumnHeading{\amx@ColumnText{\theamx@Cursor}}% + }% +} + +%% amx@amx@Indicator{}{} +%% Returns the visual blip part of the generated table. +\newcommand{\amx@amx@Indicator}[2]{% + \amx@RowColAssigned{#1}{#2}{% + \iftoggle{amx@AreAnyHighlightSet}{% + \iftoggle{amx@IsCurrentRowHighlighted}{% + \amx@Renderer@Indicator@Highlighted@Current{}% + }{% + \amx@Renderer@Indicator@Highlighted@Other{}% + }% + }{% + \amx@Renderer@Indicator{}% + }% + }{% + % This field is intentionally left blank. + }% +} + +%% amx@amx@RenderRow{} +%% Renders the row for . +\newcommand{\amx@amx@RenderRow}[1]{% + \amx@FindRowIndex{#1}% + \iftoggle{amx@AreAnyHighlightSet}{% + \iftoggle{amx@IsCurrentRowHighlighted}{% + \amx@Renderer@Row@Highlighted{\theamx@CursorR}{\amx@RowText{\theamx@CursorR}}% + }{% + \amx@Renderer@Row{\theamx@CursorR}{\amx@RowText{\theamx@CursorR}}% + }% + }{% + \amx@Renderer@Row{\theamx@CursorR}{\amx@RowText{\theamx@CursorR}}% + }% + % + \setcounter{amx@CursorC}{\value{amx@ColumnCount}}% + \stepcounter{amx@CursorC}% + \forloop{amx@Cursor}{1}{\value{amx@Cursor} < \value{amx@CursorC}}{% + & \amx@amx@Indicator{#1}{\amx@ColumnKey{\theamx@Cursor}}% + }% +} + +%% Typesets the Rows vs. Cols table, highlighting the row for the given key, or highlighting no rows if #1 is 0. +\newcommand{\amx@amx@MakeTabular}[1]{% + \renewcommand{\amx@amx@RowRenderHELPER}[1]{% + % Set the global toggle whether highlighting is enabled or not. + \ifthenelse{\equal{#1}{0}}{% + \global\togglefalse{amx@AreAnyHighlightSet}% + }{% + \global\toggletrue{amx@AreAnyHighlightSet}% + % + % Set highlight for current row. + \ifthenelse{\equal{##1}{#1}}{% + \global\toggletrue{amx@IsCurrentRowHighlighted}% + }{% + \global\togglefalse{amx@IsCurrentRowHighlighted}% + }% + }% + % + \amx@amx@RenderRow{##1} \\ + \hline% + }% + % + \begin{tabular}{|l|% + \egreg@Repeat[|]{\expandafter\theamx@ColumnCount}{c}% + |% + } + \hline + \amx@amx@RenderHeading \\ + \hline + \forlistcsloop{\amx@amx@RowRenderHELPER}{amx@Rows}% + \end{tabular}% +} +\newrobustcmd{\amxgenerate}[1][0]{% + \amx@amx@MakeTabular{#1}% +} + +%% +%% CLEARING / RESET +%% + +%% Clear all the internal data structures, undefine all commands, and reset all counters. +\newrobustcmd{\amx@Reset}{% + % Clear the data store macros: + \forloop[-1]{amx@Cursor}{\value{amx@RowCount}}{\value{amx@Cursor} > 0}{% + \expandafter\def\csname amx@Rows@\theamx@Cursor\endcsname{}% + \expandafter\def\csname amx@RowTexts@\theamx@Cursor\endcsname{}% + }% + \forloop[-1]{amx@Cursor}{\value{amx@ColumnCount}}{\value{amx@Cursor} > 0}{% + \expandafter\def\csname amx@Cols@\theamx@Cursor\endcsname{}% + \expandafter\def\csname amx@ColTexts@\theamx@Cursor\endcsname{}% + }% + % Reset the lists and counters: + \renewcommand{\amx@Rows}{}% + \setcounter{amx@RowCount}{0}% + \renewcommand{\amx@Cols}{}% + \setcounter{amx@ColumnCount}{0}% + \renewcommand{\amx@Associations}{}% + % + \setcounter{amx@CursorR}{0}% + \setcounter{amx@CursorC}{0}% + \setcounter{amx@Cursor}{0}% + % Reset customisation. + \amx@Renderer@Reset% +} +%% DANGEROUS! Clear the internal data structures! +\newrobustcmd{\amxReset}{% + \amx@Reset% +} +%% Resets the renderers to their default versions. +\newcommand{\amx@Renderer@Reset}{% + \renewcommand{\amx@Renderer@TopCorner}{\amx@Renderer@Default@TopCorner}% + \renewcommand{\amx@Renderer@ColumnHeading}[1]{\amx@Renderer@Default@ColumnHeading{##1}}% + \renewcommand{\amx@Renderer@Row}[2]{\amx@Renderer@Default@Row{##1}{##2}}% + \renewcommand{\amx@Renderer@Row@Highlighted}[2]{\amx@Renderer@Default@Row@Highlighted{##1}{##2}}% + \renewcommand{\amx@Renderer@Indicator}{\amx@Renderer@Default@Indicator}% + \renewcommand{\amx@Renderer@Indicator@Highlighted@Current}{\amx@Renderer@Default@Indicator@Highlighted@Current}% + \renewcommand{\amx@Renderer@Indicator@Highlighted@Other}{\amx@Renderer@Default@Indicator@Highlighted@Other}% +} +% Start the document with the renderers having the default version. +\amx@Renderer@Reset + +\endinput -- cgit v1.2.3