9

I'm trying to build an environment where if a page breaks in the environment some additional text is automatically printed at the end of the page, while this text is not printed when no page break occurs. So, for example:

\begin{special_env}{Please also check following page}
  A lot of text goes here...
  And even more text goes here...
\end{special_env}

Should print the text in the environment as normal, but whenever a page break occurs should add "Please also check following page" to the bottom of the page.

I know things like longtable can do this, but my text isn't really a table and I'm not sufficiently advanced in my TeX skills to figure out how they do it. I've seen Add customized text at an optional page-break, which almost does what I need except it requires me to already know approximately where the page break will be. I've also seen Add customized text at an optional page-break, which again seems to focus too much on tables (unless I'm misunderstanding).

My question is, how can I code this so that it will automatically figure out where the page breaks end up being and inserts the text where needed?

While I have some experience as a LaTeX user and have occasionally ventured into doing some slightly more advanced scripting, my knowledge is really rather limited, so please bear with me while I try to digest your answers.

[Edit]

Thanks both for your help. I have played with the different variants proposed, but haven't quite been able to achieve what I need. It's close, but not quite there yet. Let me give you a little bit more detail on what I'm trying to achieve. I am extending a class that defines a question environment for the purposes of writing exam papers. When a question continues on a new page, we're required to add "Question X continues on next page" on that page. The class currently uses an interesting method to determine whether to page break after a question.

A document then consists essentially of a \maketitle followed by a sequence of question environments, normally with no other text between them.

At the moment, my code looks somewhat like this:

\documentclass{article}

\usepackage{lipsum}

\makeatletter

\newif\ifinenv
\inenvfalse

\newcommand \@@footer{\ifinenv {QUESTION \thequestion\ CONTINUES ON NEXT PAGE} \fi}

\def \ps@exam{%
  \let \@mkboth \@gobbletwo%
  \def \@oddhead{}%
  \def \@oddfoot{\@@footer}%
  \def \@evenhead{}%
  \def \@evenfoot{\@@footer}%
}
\pagestyle{exam}

\newcommand \testpagebreak[1]{%
  \vfil%
  \penalty #1%
  \vfilneg%
}

\newcounter{question}

\newenvironment{question}{%
  \refstepcounter{question}%
  \inenvtrue
  \begin{list}{}{}%
      \item[\bf \thequestion.]% 
}{%
  \end{list}%
  \testpagebreak{-350}%
}

\begin{document}

  \begin{question}
    \lipsum[1-7]
  \end{question}

  \begin{question}
    \lipsum[8-13]
  \end{question}

  \begin{question}
    Just a single line

    And another
  \end{question}
\end{document}

This works quite well, except where the start of a question is pushed to the start of a new page. In this case, the PTO text will be printed on the page before the question starts, so for example:

Text of Question 1
Question 2 continues on the next page
----page break----
Text of Question 2

Clearly the problem is that the start of the environment of Question 2 is still processed before TeX decides to open a new page. If I replace the \testpagebreak code with a hard \newpage or leave it out completely all is fine. Is there a way to fiddle with this code to make it work with \testpagebreak (or a variant thereof)?

[/Edit]

[Edit 2]

I've experimented some more based on @Werner's idea. My code can be found at PasteBin. Note that in the second question there are two alternative versions of the contents, a short one and a longer one. Using the short one (so that Question 2 doesn't actually span multiple pages) all is well. Using the long one (so that Question 2 does span multiple pages) the "Question 2 continues" text is shown already on the last page of Question 1; that is one page too early.

From this, I deduce that the label mechanism works correctly. However, the code in the footer doesn't always correctly pick up whether a question actually starts on the page currently being shipped out. I have no idea how to fix this, but maybe someone out there can point me in a useful direction?

[/Edit 2]

Many thanks in advance,

Steffen

  • Welcome to TeX.SX! Breakable boxes/environments are always a little bit difficult. I would suggest to remove the See on next page etc. stuff from the bottom and rather print it at the bottom of the first part of the page-broken environment. You could use tcolorbox (with no colours ;-) for breaking such boxes and environments and adding this text at the bottom etc. –  Jun 26 '15 at 11:58
  • Thanks Christian. I'm not sure I fully understand your suggestion. I need this to print on the bottom of every page that has text from this environment except for the last one. I currently manually insert the text manually once I know where the page breaks are, but that's a little awkward, especially as a document gets edited over time. – Steffen Zschaler Jun 26 '15 at 12:00
  • You should show us what you have, perhaps there will be some amendments/suggestions –  Jun 26 '15 at 12:00
  • What I have is literally just a three step manual process: 1. enter main text and compile to PDF, 2. see whereabouts page breaks occur and add See on next page text in approximate location into LaTeX, 3. recompile and keep my fingers crossed. – Steffen Zschaler Jun 26 '15 at 12:19
  • Sounds as if you have plenty of time and no other work to do ;-) –  Jun 26 '15 at 12:21
  • No, I'm working with someone else's class here and am trying to reduce the amount of work I need to do... – Steffen Zschaler Jun 26 '15 at 12:25
  • Well, I've to leave my computer now, but perhaps I return to this question later on, unless some other guy attacked the problem already –  Jun 26 '15 at 12:26
  • Thanks. I've started looking into tcolorbox as you recommend, which may indeed help me address the problem. – Steffen Zschaler Jun 26 '15 at 12:32
  • Strange, there was a really interesting answer here a moment ago, but now it's gone. @ian-thompson did you delete this again? – Steffen Zschaler Jun 26 '15 at 14:09
  • @SteffenZschaler --- I deleted it because it doesn't always change the footer back at the right time. It turns out that it's quite hard to do this; at the end of the environment may be too early (because TeX holds material until it decides on a good location for a page break), but using \afterpage as in my solution can make it happen too late. – Ian Thompson Jun 26 '15 at 14:49
  • @SteffenZschaler --- tried again. Hopefully it works this time. – Ian Thompson Jun 26 '15 at 17:53
  • Idea: why not simply insure that no page break occurs in the middle of a question? – Mark Jun 28 '15 at 20:34
  • Thanks, but some of our questions require quite a bit of expose and the odd figure, so don't necessarily fit on a single page. – Steffen Zschaler Jun 28 '15 at 21:10

2 Answers2

6

What about the following idea?

It's much different from yours (or perhaps the class author's), but perhaps more robust as it uses the \label-\ref system to determine whether a page break has occurred mid-question:

enter image description here

\documentclass{article}

\usepackage[paper=a5paper,margin=1in]{geometry}% Just for this example
\usepackage{multido}% Just for this example
\usepackage[nopar]{lipsum}% Just for this example
\usepackage{refcount}
\usepackage{fancyhdr}

\newcounter{question}

\newenvironment{question}{%
    \begin{list}{}{}%
      \refstepcounter{question}%
      \item[\bfseries\thequestion.]%
      \leavevmode% Start paragraph
      \label{question-start-\thequestion}%
  }{%
    \label{question-end-\thequestion}%
    \end{list}
  }

\pagestyle{fancy}
\fancyhf{}% Clear header/footer
\fancyfoot[L]{% Left footer
  \ifnum\getpagerefnumber{question-start-\thequestion}<\getpagerefnumber{question-end-\thequestion}
    Question~\thequestion{} continues on the next page%
  \fi}
\fancyfoot[R]{See next page}% Right footer
\renewcommand{\headrulewidth}{0pt}% Remove header rule

\AtEndDocument{\fancyfoot[R]{}}% Remove right footer at end of document

\sloppypar% Just for this example
\begin{document}

\multido{\i=1+1}{50}{%
  \begin{question}
    \lipsum[\i]
  \end{question}
  \bigskip
}

\end{document}

At each \item inside question, a \label is set, and then another \label at the end of the question. A check is made to see whether the page number at the start is different from (less than) the ending page number. Accordingly, the footer sets the appropriate clause.

Werner
  • 603,163
  • Thanks, this looks very interesting indeed. I'll give it a spin once back at my main computer and report back. – Steffen Zschaler Jun 26 '15 at 21:49
  • I've now tried this. Unfortunately, it suffers from the same problem as my attempts in the edits above: when the open label is created, TeX hasn't necessarily decided yet whether to move the start of the question onto a new page, so in those cases I get the text a page too early. – Steffen Zschaler Jun 27 '15 at 12:36
  • @SteffenZschaler: Retry with the minor addition of \leavevmode... – Werner Jun 28 '15 at 17:23
  • Thanks, @werner. Unfortunately, this doesn't seem to make any difference at all. I'm not sure I fully understand how \leavevmode works, but I couldn't figure out why it would help. – Steffen Zschaler Jun 29 '15 at 09:02
  • @SteffenZschaler: It should start the setting of the list item before setting the label. – Werner Jun 29 '15 at 14:32
  • Thanks @werner. Unfortunately it doesn't seem to do this. What's the protocol on this site, am I allowed to add an answer to my own question? If so, I could use this to attach the result I'm currently seeing. Maybe you or someone else would be able to figure out what's going on... – Steffen Zschaler Jun 29 '15 at 16:09
  • @SteffenZschaler: The answer section is for answers. If you have an ongoing problem using one of the solution proposed, you can either edit your own post to show the "current state that still highlights some problem" or post content to Pastebin.org... – Werner Jun 29 '15 at 18:45
  • Thanks for the clarification of protocol, @werner. I have added the results of some more experimentation to the original question using a pastebin link to keep things reasonably compact. – Steffen Zschaler Jun 29 '15 at 19:39
  • 1
    @SteffenZschaler: I see you've mixed in your \testpagebreak with my construction. I think That's wrong. Why do you use or need \testpagebreak? Is it because you need to leave a specific amount of space at the bottom of a page blank? Or perhaps because you need space left blank after a question? In that regard, one could also use needspace. Regardless, I'm not entirely clear on the need for using \testpagebreak. – Werner Jun 29 '15 at 20:15
  • \testpagebreak is what the current class uses to determine whether or not to start a new page after a question (and, in fact, after sub-questions etc.). I believe it is an attempt to balance readability in exam conditions (ideally every question on one page) with wasting paper (ideally, all questions on one page). I don't like it very much, but am trying to resolve one issue at a time. needspace looks like it might give me a better way of expressing the above intention, so I'll have a play to see if it also fixes the problem with the PTO text. – Steffen Zschaler Jun 30 '15 at 08:49
  • Excellent. This has worked. I have had to combine it with the \inenv idea from @ian-thompson to ensure it doesn't print the PTO on the final page of a question (see PasteBin). Many thanks, @werner. – Steffen Zschaler Jun 30 '15 at 09:26
1

My original idea was to change the footer at the environment start and revert it at the end, but this fails if the environment ends whilst TeX is storing material that will ultimately contain a page break (most likely if the environment end ends up near the top of a page).

I think the right way to do this is to put a switch in the footer itself, to detect whether or not the environment is active when the page is constructed. I've used the fancyhdr package because it makes changing the footer very easy, but it isn't strictly necessary. Similarly, I've used the geometry package to adjust the page dimensions and move the end of the environment from place to place, but this is just for testing purposes. Finally, note that there is no need to execute \inenvfalse at the end of the environment, because \inenvtrue is local, and the global setting is restored at \end{myenv}.

\documentclass{article}
\usepackage[width=16cm,height=20cm]{geometry}
\usepackage{lipsum} % For dummy text
\usepackage{fancyhdr}

\pagestyle{fancy}
\newif\ifinenv
\inenvfalse
\newcommand\myrfoot{\ifinenv PTO \else Hello! \fi}
\rfoot\myrfoot

\newenvironment{myenv}
{\section*{Environment start!}\inenvtrue}
{\par\medskip\noindent\centering\rule{0.75\textwidth}{2pt}\par\bigskip}
\begin{document}
\lipsum[1-8]
\begin{myenv}
\lipsum[9-16]
\end{myenv}
\lipsum[17-24]
\end{document}
Ian Thompson
  • 43,767