# Creating a Matrixlist package

I haven't been able to find a suitable package that does what I want. The closest is parcolumns and I've spent several hours trying to understand TeX programming and the parcolumns style. While I got the most of it I've tried to tweak it and just can't get it to do what I want.

I'm curious if anyone either knows of a package or can write one up quickly that does the following:

1. You give it a \\ terminated list just like enumerate and the number of columns;

2. It internally groups the list by number of columns. (a,b,c,d,e) with columns=2 will be grouped as ((a,b,c),(d,e));

3. It then creates m rows (\hboxes, depending on the number of elements and column size). The nth row contains an \hbox of the nth element in each group. This creates a matrix

a d
b e
c

4. Each element in the row tries to distribute itself evenly along the horizontal BUT if on element overlaps the next it will "push" it INSTEAD of overlapping it (and this will continue until there is no need to push);

5. No gaps between rows AND no end gap on last column (so one has to get the width of the largest element in the last column and set the column size to that).

The point here is we have a matrix of boxes BUT if the horizontal content of one box is larger than the space it is given it will simply shift the adjacent box over to make room for it BUT if not it will align in a distributed manner.

Hopefully that makes sense and there is already a package that does this. With parcolumns I have two issues: When my elements are horizontally too large (even if just a little) they overlap the next column and I have to manually push that next element over (which may cause a chain reaction).

\documentclass{article}
\usepackage{tikz}
\scrollmode

\begin{document}

\newcommand{\drawrect}[1]{\fbox{\begin{tikzpicture} \fill (-#1,-1) rectangle (#1,1);\end{tikzpicture}}}

\noindent\fbox{\hbox to \linewidth{%
\drawrect{1.5}\hspace*{\fill}\drawrect{1.5}\hspace*{\fill}\drawrect{1.5}\\}}
\fbox{\hbox to \linewidth{\drawrect{2}\hspace{0.2cm}\drawrect{1.5}\hspace{1.2cm}\drawrect{1.5}\\}}
\fbox{\hbox to \linewidth{\drawrect{2.5}\hspace{0.2cm}\drawrect{1.5}\hspace{0.2cm}\drawrect{1.5}\\}}
\fbox{\hbox to \linewidth{\drawrect{2.4}\hspace{0.4cm}\drawrect{1.5}\hspace{0.2cm}\drawrect{1.5}\\}}

\end{document}


Here is an example situation

1. Note that the first element of row 3 "pushes" or overlaps into the 2nd element of row.
2. This causes the 2nd element to be offset by some amount (user specified). The 3rd element does not change positions though.
3. In row 4, the first element is slightly smaller BUT note that the 2nd element is aligned with the one right above it BECAUSE it snaps to that position to for visual reasons.
4. Also, if you were to add a fixed amount of whitespace to each element in the last column then you would end up causing problems (depends on how you set it up though). I want to remove this issue. To fix it we basically have to remove the whitespace so that at least one element in the last column has no whitespace. Hence we just "substract" the appropriate amount of whitespace from all columns and then at least one will have no whitespace. Note that this is only for calculating the column spacing. Essentially we just compute (\linewidth + x)/#columns where x is the smallest amount of whitespace from the set of cells in the last column. This effectively increases the \linewidth by the unused whitespace in the last column.
-
Can you clarify the first point (enumerate doesn't use \\  separators it uses \item) and the last point (you say the width of the last column is that of its widest entry, but what of other columns? widest entry in that column?) finally you say the entries are hboxes, but you compare with paracolumns which takes multiline material rather than hboxes as its items? –  David Carlisle May 12 '12 at 0:36
@DavidCarlisle 1. I "obviously" meant a tabular(but basically the &'s are "computed"(actually I was just thinking of a simple list. What I really want to do is avoid having to use special macros to designate the a new element. Maybe &\\ could be used to mean start new "element") –  Uiy May 12 '12 at 0:43
2. In parcolumns the last column will have extra space. Why? Because the column size, by default, is evenly distributed as \linewidth div numcolumns. But suppose your last column has elements that use almost no width? This will mean that there will be a lot of white space at after these elements AND visually it will look like the whole matrix is off center to the left. The goal is to shift the box back to the right to center the matrix. Do this this all you have to do is shift the whole matrix by the smallest amount of whitespace that exists in the last column. –  Uiy May 12 '12 at 0:47
if it were a tabular (and an earlier, presumably related question) asked about multicol and longtable then the columns would always be vertically aligned and one wide entry in column n would push the entire next column to the right, but your description above makes it sound as if you want the displacement just to affect that one row? –  David Carlisle May 12 '12 at 0:48
3. parcolumns does not use hboxes internally for it's rows. You can use them or not. by hbox I really just mean a self contained row. I'm thinking that what I want would be implemented a set of rows rather than a set of cells or set of columns. parcolumns implements it as a set of columns. Basically I would think it would be implemented as \vbox{\hbox{}\hbox{}...} –  Uiy May 12 '12 at 0:51

Well,... visually aligning boxes depending on rows above and below isn't really the tex way (not impossible, but....) I'd go for a layout like this, where the entries are just equally spaced in the rows.

To get each of the boxes (or if you want, just the boxes in the last column) to be natural width rather than a specified width of short, use \begin{minipage}{\xxx} for fixed boxes and \begin{varwidth}{\xxx} for the boxes on at least the last column where \xxx is textwidth divided by number of columns, adjusting for any space or rules between columns. varwidth from the package of the same name is like minipage but sets the box to a narrower width of possible.

If you use varwidth in the last column, the entire construct will not be full width, but can just be centered (with \centering in that case) as I think you wanted.

If that layout is acceptable, the other syntactic issues, like calculating column width and entering cells in column major rather than row major order can be sorted if need be.

\documentclass{article}
\usepackage{tikz}
\scrollmode

\begin{document}

\noindent X\dotfill X

\noindent X\dotfill X

\newcommand{\drawrect}[1]{\fbox{\begin{tikzpicture} \fill (-#1,-1) rectangle (#1,1);\end{tikzpicture}}}

\def\onerow#1{\par\noindent\fbox{%
\dimen0=\textwidth
\hbox to \dimen0{#1}}}

\onerow{\drawrect{1.5}\hfill\drawrect{1.5}\hfill\drawrect{1.5}}
\onerow{\drawrect{2}\hfill\drawrect{1.5}\hfill\drawrect{1.5}}
\onerow{\drawrect{2.5}\hfill\drawrect{1.5}\hspace{0.2cm}\drawrect{1.5}}
\onerow{\drawrect{2.4}\hfill\drawrect{1.5}\hspace{0.2cm}\drawrect{1.5}}

\end{document}

-
Unfortunately your 2nd row is very unaesthetic to me compare your 2nd row with mine. Surely you would agree mine is more visually appealing? It should not be difficult at all to the alignment to previous rows. Simply keep a history of the previous column snap. (e.g., for each column we have a variable that represents the offset from equal distribution(linewidth/3 or whatever). Generally this is 0. But when we have an overlap we set this to how much we had to push the cell to avoid the overlap. If there was no overlap it gets set to 0. Cells will just use this value in there hspace. –  Uiy May 12 '12 at 2:00
For example, when we go through row one we set up offset_k = 0. When we go through the 2nd row we use offset_k for the kth column offset. In this case since there is no overlap the offsets will be 0 and you will end up like my examples' 2nd row. When we get to the 3rd row we see the first element is overlapping into the 2nd by some amount. We take this amount it extends into the 2nd column and add some user defined amount then set offset_2 to be this amount. This will cause the 2nd element of the 3rd row to be offset by this amount AND the 4th row's 2nd element(almost) –  Uiy May 12 '12 at 2:03
The only trick is to make it "fuzzy" so that we have to reset the offsets or change them depending on their magnitude. For example, if the offset_k was very large but our push for the current row was very small we might want to use our user defined amount + the new offset. (sort of ignore the previous offset_k because it was much larger than we new one) –  Uiy May 12 '12 at 2:06
"Surely you would agree mine is more visually appealing?" well no actually, all the others look like the 2nd item is centred between the 1st and 3rd, and so that one looks misplaced. But personal preferences are personal:-) –  David Carlisle May 12 '12 at 2:07
In any case, it shouldn't be hard to do... and if I actually could understand the tex programming I probably could do it myself ;/ Maybe if you could write up a simple package environment where it would do the distribution evenly BUT by using those offset_k's then I might be able to modify them to in the proper way. –  Uiy May 12 '12 at 2:09