20

So, the designers did their job and specified coloured backgrounds and rounded corners for all tables. Like so:

enter image description here

As described here, this requires doing nasty things like putting the whole table into a savebox, measuring the size of that, then setting a clipping path, and then painting the table.

Now the question is: What if this were a multi-page table, printed with longtable or supertabular? Any chance of intercepting the part written on each page to do the same kind of nastiness to it?

Preferably, of course, the exact nastiness would depend on whether this was the first or the last, or one of the intermediate chunks of the table.

\documentclass{article}
\usepackage[dvipsnames,table]{xcolor}
\usepackage{array}
\usepackage{environ}
\usepackage{tikz}

\newsavebox{\tablebox}
\definecolor{tablecolor}{named}{ForestGreen}

\NewEnviron{rndtable}[1]{%
  \addtolength{\extrarowheight}{1ex}%
  \rowcolors{2}{tablecolor!20}{tablecolor!40}%
  \sffamily%
  \newcommand{\header}[1]{%
    \multicolumn{1}{c}{%
      \cellcolor{tablecolor}\color{white}\bfseries##1}}
  \savebox{\tablebox}{%
    \begin{tabular}{#1}%
      \BODY%
    \end{tabular}}%
  \begin{tikzpicture}
    \clip[rounded corners=1ex] (0,-\dp\tablebox) -- (\wd\tablebox,-\dp\tablebox) -- (\wd\tablebox,\ht\tablebox) -- (0,\ht\tablebox) -- cycle;
    \node at (0,-\dp\tablebox) [anchor=south west,inner sep=0pt]{\usebox{\tablebox}};
    \draw[tablecolor,very thick,rounded corners=1ex] (0,-\dp\tablebox) -- (\wd\tablebox,-\dp\tablebox) -- (\wd\tablebox,\ht\tablebox) -- (0,\ht\tablebox) -- cycle;
  \end{tikzpicture}
}

\begin{document}
\noindent
\begin{rndtable}{cccp{5cm}l}
  \header{vote} &
  \header{answer} &
  \header{views} &
  \header{question} &
  \header{user} \\
  1 & 1 & 20 & How can I improve this table (using tabularx)? & Jubobs 21.3k\\
  0 & 0 & 3 & References alignment problem in IEEtrans & Prateek Jain 1\\
  1 & 1 & 29 & Problem with cases environment when used in a stack & Steven B. Segletes 32.2k\\
  1 & 0 & 85 & TikZ error for externalized graphics but output is correct & henry 1,033\\
  0 & 0 & 12 & Working with leaflets & Claudio Fiandrino 33.1k\\
\end{rndtable}

\end{document}
mabartibin
  • 1,826
  • 3
    you should be able to use colortbl to colour the table and (just) use tikz rounded boxes on the head and foot – David Carlisle Apr 28 '14 at 12:21
  • Well, to keep the coloured background within the rounded boxes, I need to set a clipping path before painting the boxes. Or were you suggesting not using colortbl for the colouring of the headers at all, but somehow putting TikZ nodes around the cells of the header/footer? – mabartibin Apr 28 '14 at 12:25
  • more or less, since you want the same colour across the full with of the table in that case. I'd just grab the box \LT@head stick a tikz background on it and then put it back before longtable notices that it's changed... – David Carlisle Apr 28 '14 at 12:30
  • Feeling stupid. I tried redefining \endhead so it puts the header into a different box register, which I can then do things to, before writing the results into \LT@head, but already \def\endhead{\LT@end@hd@ft\LT@pre@head\setbox\LT@head=\box\LT@pre@head} fails miserably. The header isn't shown. – mabartibin Apr 28 '14 at 14:05
  • sorry only got time to give hints now, may answer later if no one else has – David Carlisle Apr 28 '14 at 14:08
  • @DavidCarlisle Do you feel motivated for an answer? :) – percusse Jul 13 '15 at 21:43
  • @percusse I guess I volunteered for that, but too late tonight (and I may need help with the tikz bits:-) – David Carlisle Jul 13 '15 at 22:09
  • @DavidCarlisle No problem. At your service. – percusse Jul 13 '15 at 22:18
  • Yes please! Never got this to work properly. Though, unbelievably, the proposal got accepted with unrounded corners on the tables :-O – mabartibin Jul 14 '15 at 05:20
  • @DavidCarlisle I posted my feeble attempt below if you want to take a look; probably best to just use my TikZ stuff and throw out the rest. :-) – Paul Gessler Dec 23 '15 at 21:16

1 Answers1

1

This is a partial answer; I've marked it CW and I hope others (looking at you dpc... :-) can help finish it up.

Alternatively, there may be a much better way to do this. If that's the case, feel free to steal my TikZ bits and I will simply delete the post once a better answer comes along.

My initial idea was to hack up the definition of \LT@end@hd@ft, which is used to process the various "special chunks" of a longtable, such as \endhead, \endfirsthead, etc. Once the chunk is processed and put in the appropriate box (\setbox##1\box\z@ in my code below), we can use \ifx tests to check which piece we're handling and then modify the box contents accordingly.

My code only messes with \LT@firsthead (the \firsthead contents), but these conditionals could be nested to do special things with any of the special chunks as desired.

Status: the idea works, but there are some problems I do not understand. Probably some stupid mistakes on my part. Here are the problems:

  1. The first header row (the one I messed with) takes the full width of the textblock, rather than the natural width of the table. I think this might have to do with longtable's trial process, so it can probably be solved by modifying the box at a different time than I did.
  2. The last row, where we'll need to clip the bottom corners. If the user adds \endlastfoot, we can use a similar approach as for \endfirsthead. However (as is the case here), not all tables will have special rows at the table foot.
  3. Adding the border around the middle chunks. Also included here would be rounding at the top and bottom of each continued page if desired. This could be done with continued page headers and footers, but again, not all tables will have these.

I think all of these problems could be solved by somebody with deeper knowledge of longtable than I. So, as I said, feel free to use my TikZ code to extend/fix up the solution. All my TikZ commands have a single argument, the box to operate on. I think the better place for this stuff might be in the output section, but my attempts there failed spectacularly.

I also adjusted the code a bit so that styles are shared between the short and long tables, which should make it easier to change the style globally.

Here's the code as it sits now. The longtable example has enough rows to cover a partial page at the start, a full page in the middle, and a partial page at the end, for testing the various scenarios.

\documentclass{article}
\usepackage[dvipsnames,table]{xcolor}
\usepackage{environ}
\usepackage{tikz}
\usepackage{longtable}
\usepackage{showframe} % just for testing...

% test commands
\def\Z{  0 & 0 & 12 & Working with leaflets & Claudio Fiandrino\\}
\def\ZZ{\Z\Z\Z\Z}\def\ZZZ{\ZZ\ZZ\ZZ\ZZ}\def\ZZZZ{\ZZZ\ZZZ\ZZZ\ZZZ}

% some stuff common to short and long tables
\definecolor{tablecolor}{named}{ForestGreen}
\newcommand{\header}[1]{%
  \multicolumn{1}{c}{%
    \cellcolor{tablecolor}\color{white}\bfseries#1}}
\newcommand{\rndtablesetup}{%
  \addtolength{\extrarowheight}{1ex}%
  \rowcolors{2}{tablecolor!20}{tablecolor!40}%
  \sffamily}

% styles for the clipping/internal nodes
\tikzset{
  myclip/.style={rounded corners=1ex},
  mynode/.style={anchor=south west,inner sep=0pt,outer sep=0pt},
  mybord/.style={myclip,very thick,tablecolor},
}

% the short table (provided)
\newsavebox{\tablebox}
\NewEnviron{rndtable}[1]{%
  \rndtablesetup%
  \savebox{\tablebox}{%
    \begin{tabular}{#1}%
      \BODY%
    \end{tabular}}%
  \begin{tikzpicture}
    \clip[myclip] (0,-\dp\tablebox) -- (\wd\tablebox,-\dp\tablebox) --
      (\wd\tablebox,\ht\tablebox) -- (0,\ht\tablebox) -- cycle;
    \node[mynode] at (0,-\dp\tablebox) {\usebox{\tablebox}};
    \draw[mybord] (0,-\dp\tablebox) -- (\wd\tablebox,-\dp\tablebox) --
      (\wd\tablebox,\ht\tablebox) -- (0,\ht\tablebox) -- cycle;
  \end{tikzpicture}}

% round top
\newcommand{\roundtop}[1]{%
  \begin{tikzpicture}
    \clip[myclip] (0,0) |- (\wd#1,\ht#1+\dp#1) -- (\wd#1,0);
    \draw[mybord] (0,0) |- (\wd#1,\ht#1+\dp#1) -- (\wd#1,0);
    \node[mynode] at (0,0) {\box#1};
  \end{tikzpicture}}

% round bottom
\newcommand{\roundbot}[1]{%
  \begin{tikzpicture}
    \clip[myclip] (0,0) |- (\wd#1,-\ht#1+\dp#1) -- (\wd#1,0);
    \draw[mybord] (0,0) |- (\wd#1,-\ht#1+\dp#1) -- (\wd#1,0);
    \node[mynode] at (0,0) {\box#1};
  \end{tikzpicture}}

% frame midsections
\newcommand{\framemid}[1]{%
  \begin{tikzpicture}
    \draw[mybord] (0,0) -- (0,\ht#1+\dp#1) (\wd#1,0) -- (\wd#1,\ht#1+\dp#1);
    \node[mynode] at (0,0) {\box#1};
  \end{tikzpicture}}

% the long table (work in progress)
\makeatletter
\NewEnviron{longrndtable}[1]{%
  \rndtablesetup%
  \def\LT@end@hd@ft##1{%
  \LT@echunk
  \ifx\LT@start\endgraf
    \LT@err
     {Longtable head or foot not at start of table}%
     {Increase LTchunksize}%
  \fi
  \setbox##1\box\z@
  \ifx\LT@firsthead##1
    \setbox##1=\hbox{\roundtop{##1}}
  \fi
  \LT@get@widths
  \LT@bchunk}
  \begin{longtable}{#1}%
    \BODY%
  \end{longtable}%
}
\makeatother

\begin{document}
\noindent
\begin{rndtable}{cccp{4cm}p{3cm}}
  \header{vote} &
  \header{answer} &
  \header{views} &
  \header{question} &
  \header{user} \\
  \ZZ
\end{rndtable}

\begin{longrndtable}{cccp{4cm}p{3cm}}
  \header{vote} &
  \header{answer} &
  \header{views} &
  \header{question} &
  \header{user} \\
  \endfirsthead
  \header{vt} &
  \header{ans} &
  \header{vws} &
  \header{q} &
  \header{u} \\
  \endhead
  \ZZZZ \ZZZ
\end{longrndtable}

\end{document}

enter image description here

Paul Gessler
  • 29,607
  • Hi Paul! Thanks for your efforts. It seems the left and right margins are getting in the way. At least when I say \setlength\LTleft{0pt}, things look right at the left end. The same with LTright doesn’t work as well :-/ – mabartibin Jan 28 '16 at 13:28