[Tex/LaTex] Ensuring a paragraph uses at least a given height

memoirspacingstrutvertical alignment

I'm making a custom document class based on memoir, and I don't know how to implement the chapter precis so that it does what I want (the chapter precis is a small optional paragraph that follows chapter headings).

I'd like the actual first paragraph of the chapter to start at a fixed vertical position below the chapter heading, unless the precis is very long, in which case it should push the first paragraph down. Here's what it currently looks like:

Chapter heading and precis

I have \setlength{\afterchapskip}{4\baselineskip} (distance from chapter heading to 1st paragraph), and \setlength{\prechapterprecisshift}{-3\baselineskip} (taken out of \afterchapskip if there is a precis). If I don't find a solution, I'll arrange for the spacing after the precis to be 2\baselineskip so one-line precis won't move the 1st paragraph. However, I'd like two-lines precis to still not push the 1st paragraph down.

Given the way memoir defines \chapterprecis and offers \prechapterprecis and \postchapterprecis hooks, I'm not sure how I can measure the height of the precis. I've also thought making about some sort of paragraph-level strut, but I don't know how (inserting a normal zero-width rule at the beginning of the precis text changes the height of its first line, not of the precis as a whole).


Edit — my current solution

I've slightly adapted @Gonzalo's approach to simplify the height comparison. The minibox also needed its [t] argument:

\newlength{\postchapterprecisskip}
\setlength{\prechapterprecisshift}{3\baselineskip}
\setlength{\postchapterprecisskip}{\baselineskip}
\renewcommand\prechapterprecis{\vspace*{-\prechapterprecisshift}}
\renewcommand\postchapterprecis{\vspace*{\postchapterprecisskip}}
\newsavebox\sba@precisbox
\newlength\sba@precisboxht
\newlength\sba@precisboxdp
\renewcommand\chapterprecishere[1]{%
    \begin{lrbox}{\sba@precisbox}%
        \begin{minipage}[t]{\linewidth}%
            \prechapterprecis
            \flushright
            \begin{balanced}{\linewidth}%
                \precisfont\strut##1\strut%
            \end{balanced}%
            \postchapterprecis
        \end{minipage}%
    \end{lrbox}%
    \settoheight\sba@precisboxht{\usebox\sba@precisbox}%
    \settoheight\sba@precisboxdp{\usebox\sba@precisbox}%
    \addtolength\sba@precisboxht{\sba@precisboxdp}%
    \usebox{\sba@precisbox}\par\unskip%
    \ifnum\sba@precisboxht<0pt
        \vspace*{-\sba@precisboxht}
    \fi}

For chapters with a precis it works nicely, with a consistent vertical position of the first chapter that gets pushed down as soon as the precis takes more than 2 lines.

Correct: aligned first paragraphs

Correct: 3-line precis pushes down

However, there is a slight shift compared to the first paragraph without a precis (slightly lower. That shift is influenced by adding \hrule so I'm guessing it's an issue with \par or \parskip… any idea?

Incorrect


Edit — Accepted solution

I haven't had much time to adopt one particular solution in my code; I've accepted David's answer because it uses an original technique, but Gonzalo's is probably a bit more general, with some tweaking of the surrounding whitespace.

Best Answer

As an alternative to boxing, this just uses \prevgraf to see how many lines were in the previous paragraph and adds \baselineskip spacing if it is less than a certain amount (3) in this example, which means that 1,2 or 3 line paragraphs take the same space but a 4 line one pushes the following text down.

Please note you should always provide a full working document in the question: as you didn't I have borrowed one from Gonzalo's answer.

\documentclass[openany]{memoir}% option openany just for the example
\usepackage{lipsum}


\renewcommand\chapterprecishere[1]{%
  \prevgraf0
  \prechapterprecis #1\postchapterprecis
  {\count0 \numexpr3-\prevgraf\relax
    \precisfont% just needed in case this did a size change so get right baselien
   \ifnum\count0 >0 \vspace{\count0 \baselineskip}\fi}}

\begin{document}

\chapter{Test Chapter One}
\chapterprecishere{Test test test test test test test test test test test test test 
test test test test test test test test test test test test test test test test}
\lipsum[4]
\chapter{Test Chapter Two}
\chapterprecishere{Test test test test test}
\lipsum[4]
\chapter{Test Chapter Three}
\chapterprecishere{Test test test test test test test test test test test test test test 
test test test test test test test test test test test test test test test test test test test 
test test test test test test test}
\lipsum[4]
\chapter{Test Chapter Four}
\chapterprecishere{Test test test test test test test test test test test test test test 
test test test test test test test test test test test test test test test test test test test 
test test test test test test test test test test test test test test test test test test}
\lipsum[4]
\chapter{Test Chapter Five}
\chapterprecishere{} % need this or need to hook the measuring code elsewhere
\lipsum[4]
\chapter{Test Chapter Six}
\chapterprecishere{Test test} 
\lipsum[4]


\end{document}

If \postchapterprecis might use some decoration such as a (latex) rule or other decoration that resets \prevgraf a more general version would save \prevgraf and \baselineskip inside the precis, and then use them outside to adjust the spacing, so

\renewcommand\chapterprecishere[1]{%
  \prevgraf0
  \prechapterprecis #1%
  \par
  \xdef\precistmp{\noexpand\precisskip{\the\prevgraf}{\the\baselineskip}}%
  \postchapterprecis
  \precistmp}

so \precistmp will expand to something like

 \precisskip{3}{25pt}

so you need to define that command to do whatever you want to do if there was a 3 line paragraph on 25pt baseline. Say:

\def\precisskip#1#2{{%
    \count0 \numexpr3-#1\relax
    \dimen0=#2 %
   \ifnum >0 \vspace{\count0 \dimen0}\fi}}