1

I have a document which pulls in an external .tex file which is procedurally generated from a database and then interpreted into a multiple page table-like graphic written in TikZ.

However, when I hit a pagebreak I need to be able to add a header line much like longtable does. At the moment I'm using the everypage package, but that is really suboptimal because it doesn't play very nice with memoir, destroys my margins, adds a third reference to deal with (separate from both memoir and TikZ current page positioning). It also runs its code after the page has been executed (as far as I can tell?) which makes it difficult to reference things that happened on the previous page.

I have tried to read longtable but didn't get very far—it's impressive but a bit cryptic without guidance.

What is the correct way to implement a longtable-like repeating header for a table-shaped graph?

Here's an MWE of something I tried:

In theory, this should check each time it makes an \exampleblock to see if there's a header on the page, and if not, then it adds one. It works fine on the first page, but is always two blocks too low after that—I don't really know why.

% !TEX TS-program = xelatex

\documentclass[showtrims]{memoir}
\usepackage{tikz}

\setstocksize{11in}{8.5in}
\settrimmedsize{8.5in}{5.5in}{*}
\settrims{1in}{1in}
\setulmarginsandblock{1in}{1in}{*}
\setlrmarginsandblock{1in}{.75in}{*}

\checkandfixthelayout

\newcounter{headeronpage}

\newcommand\exampleblock{\vfill%
    \ifnum\value{headeronpage}<\value{page}%
        \headerthing\vfill\fi%
    \noindent\tikz\draw(0,0)rectangle%
    (\linewidth,12ex)node[pos=.5]%
    {I'm a fancy TikZ drawing!};%
}

\newcommand\headerthing{%
    \setcounter{headeronpage}{\value{page}}%
    \noindent\tikz\draw (0,0)%
    rectangle (\linewidth,4ex)%
    node[pos=.5]{I'm a header thing!};%
}

\begin{document}

    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock

\end{document}

How is this challenge handled in packages like longtable?

Just to clarify: I know fancyhdr and stuff (though don't know how they work under the hood), what I'm trying to do isn't that kind of header, but more of a long table.

Ryan
  • 2,914
  • 1
    "It also runs its code after the page has been executed" the page breaking always happens after all macros on the page (and perhaps following pages) are executed and all text has been typeset. that is the basic mechanism of tex's page breaker which is asynchronous with respect to the macro expansion and paragraph building systems. – David Carlisle May 12 '15 at 09:02
  • Since you know your widths in advance (I think) the simplest is to put the heading in the page head using fancyhdr or memoir's heading facilities (if they are different). – David Carlisle May 12 '15 at 09:04
  • @DavidCarlisle I must admit I haven't tried putting my tikzpicture inside a fancyhdr, but that sounds like a bit of a margin calculating nightmare... I'd much prefer if I could somehow have it actually inside the typeblock—is that impossible? How did you solve this problem when you wrote longtable? – Ryan May 12 '15 at 09:08
  • longtable replaces the standard output routine with its own so it takes control of the full page makeup including headers footers etc, and also why it doesn't work with say multicol (as that is doing the same) but also note that the longtable headers do not depend on the table content as they are set at a different time. (the dependency on column widths is handled indirectly and requires multiple latex runs) – David Carlisle May 12 '15 at 09:21
  • Do you think it's possible to use \pagetotal to measure if there's enough space left over for another block, and insert a \headerthing if there's not enough space? – Ryan May 12 '15 at 09:27
  • longtable inserts always the same header (it is a box) so I doubt that you want really the same as longtable. Beside this you have imho this choices: Place labels everywhere, compare the \pageref of two following blocks and insert a heading if they differ. This needs multiple latex runs and can take some time until it settles. Or insert your heading by putting it in the header. Measuring pagetotal should work too - look at the needspace package. – Ulrike Fischer May 12 '15 at 09:27
  • @UlrikeFischer I tried needspace, but couldn't seem to get it to work. I may have a solution now though. – Ryan May 12 '15 at 09:43

1 Answers1

2

I think I may have found a solution:

(based on this question and answer)

% !TEX TS-program = xelatex

\documentclass[showtrims]{memoir}
\usepackage{tikz}

\setstocksize{11in}{8.5in}
\settrimmedsize{8.5in}{5.5in}{*}
\settrims{1in}{1in}
\setulmarginsandblock{1in}{1in}{*}
\setlrmarginsandblock{1in}{.75in}{*}

\checkandfixthelayout

\newcounter{headeronpage}

\newlength\blockheight
\setlength\blockheight{.5in}

\newcommand\exampleblock{\vfill%
    \ifnum\dimexpr\pagetotal+\blockheight>\textheight%
        \headerthing\vfill\fi%
    \noindent\tikz\draw(0,0)rectangle%
    (\linewidth,\blockheight)node[pos=.5]%
    {Pagetotal says \the\pagetotal 
    and the text is \the\textheight};%
}

\newcommand\headerthing{%
    \setcounter{headeronpage}{\value{page}}%
    \noindent\tikz\draw (0,0)%
    rectangle (\linewidth,4ex)%
    node[pos=.5]{I'm a header thing!};%
}

\begin{document}

    \headerthing

    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock
    \exampleblock

\end{document}

The key difference is instead of checking \value{page}, I'm measuring from the top using \pagetotal and then placing a header if the next block won't fit:

\ifnum\dimexpr\pagetotal+\blockheight>\textheight\headerthing\vfill\fi%
Ryan
  • 2,914
  • This is safe here as the \vfill at the start of each block exercises the page builder, and the blocks themselves don't stretch so \pagegoal is more or less trustworthy. the problem in general if you have paragraphs of text is that a single paragraph is executed as a unit (and \pagegoal is not changed during that time) but after being broken into lines may cause one or more page to be filled, but that general difficulty doesn't apply in your case. – David Carlisle May 12 '15 at 09:55
  • To see the general case, change to \newcommand\exampleblock{\space% so all the blocks are a paragraph broken into lines, one block per line and see the value of \pagegoal and lack of header on page 2. – David Carlisle May 12 '15 at 09:55
  • @DavidCarlisle Thanks for the feedback, yeah, I can get away with it here because my graphics are a perfect grid (in my actual implementation). What do you mean by "exercises the page builder" though? – Ryan May 12 '15 at 10:57
  • at certain "interesting" points (read the afterpage doc for a full list:-) TeX interrupts its processing and decides whether to invoke the output routine, which if invoked has to decide whether to make up pages out of the currently typeset material. \vfill being a vertical command forces tex into vertical mode between each of your \exampleblock and that is enough to trigger the page breaker, which doesn't decide to break the page in most cases, but it does reset \pagetotal without the \vfill \pagetotal doesn't change and so the test for a heading doesn't work. – David Carlisle May 12 '15 at 11:21