27

How can I set the width of an epigraph for automatic fitting of text inside epigraph?

I would like that the line between text and source have the same width of the above text. This in every epigraph!

Example of what I don't like:

  1. Too long a line

    \setlength{\epigraphwidth}{0.8\textwidth}
    \epigraph{All models are wrong, but some are useful.}{George E. P. Box}
    

    Too long a line

  2. Too short a line and it adds a new line that I don't like

    \epigraph{All models are wrong, but some are useful.}{George E. P. Box}
    

    enter image description here

UPDATE: the miminal source

\documentclass{book}
\usepackage[italian]{babel}

\usepackage{epigraph}
\renewcommand{\epigraphsize}{\small}

%\setlength{\epigraphwidth}{0.8\textwidth}

\renewcommand{\textflush}{flushright} \renewcommand{\sourceflush}{flushright}

\let\originalepigraph\epigraph 
\renewcommand\epigraph[2]{\originalepigraph{\textit{#1}}{\textsc{#2}}}

\begin{document}

\epigraph{All models are wrong, but some are useful.}{George E. P. Box}

\end{document}
lockstep
  • 250,273
Alberto
  • 1,887

3 Answers3

27

Heavy surgery on the \epigraph macro seems to do what you're looking for. With the help of the varwidth package we're able to compute the real width of the text (thanks to David Carlisle for the suggestion).

\documentclass{book}
\usepackage[italian]{babel}

\usepackage{epigraph,varwidth}

\renewcommand{\epigraphsize}{\small}
\setlength{\epigraphwidth}{0.6\textwidth}
\renewcommand{\textflush}{flushright}
\renewcommand{\sourceflush}{flushright}
% A useful addition
\newcommand{\epitextfont}{\itshape}
\newcommand{\episourcefont}{\scshape}

\makeatletter
\newsavebox{\epi@textbox}
\newsavebox{\epi@sourcebox}
\newlength\epi@finalwidth
\renewcommand{\epigraph}[2]{%
  \vspace{\beforeepigraphskip}
  {\epigraphsize\begin{\epigraphflush}
   \epi@finalwidth=\z@
   \sbox\epi@textbox{%
     \varwidth{\epigraphwidth}
     \begin{\textflush}\epitextfont#1\end{\textflush}
     \endvarwidth
   }%
   \epi@finalwidth=\wd\epi@textbox
   \sbox\epi@sourcebox{%
     \varwidth{\epigraphwidth}
     \begin{\sourceflush}\episourcefont#2\end{\sourceflush}%
     \endvarwidth
   }%
   \ifdim\wd\epi@sourcebox>\epi@finalwidth 
     \epi@finalwidth=\wd\epi@sourcebox
   \fi
   \leavevmode\vbox{
     \hb@xt@\epi@finalwidth{\hfil\box\epi@textbox}
     \vskip1.75ex
     \hrule height \epigraphrule
     \vskip.75ex
     \hb@xt@\epi@finalwidth{\hfil\box\epi@sourcebox}
   }%
   \end{\epigraphflush}
   \vspace{\afterepigraphskip}}}
\makeatother

\begin{document}

\epigraph{All models are wrong, but some are useful.}{George E. P. Box}
\epigraph{All models are wrong, but some are usefull.}{George E. P. Box}
\epigraph{All models are wrong, but some are usefulll.}{George E. P. Box}
\epigraph{All models are wrong, but some are usefullll.}{George E. P. Box}
\epigraph{All models are wrong, but some are more useful.}{George E. P. Box}
\epigraph{All models are wrong, but some are more and more useful.}{George E. P. Box}

\end{document}

enter image description here

egreg
  • 1,121,712
14

If you want each epigraph to be the width of its line, you could just measure the width of the first argument and set the width inside your redefined epigraph command. I've loaded the calc package to do this easily. Since the measurement of the argument needs to take into account the formatting you set for the epigraph, it's better to use the correct epigraph methods for doing this. So I've created a formatting command which then is used inside a custom environment which is passed to the relevant epigraph commands.

\documentclass{book}
\usepackage[italian]{babel}

\usepackage{epigraph}
\usepackage{calc}

\newcommand{\mytextformat}{\itshape\epigraphsize}
\newenvironment{mytext}{\mytextformat}{}
\newenvironment{mysource}{\scshape\hfill}{}
\renewcommand{\textflush}{mytext} 
\renewcommand{\sourceflush}{mysource}

\let\originalepigraph\epigraph 
\renewcommand\epigraph[2]%
   {\setlength{\epigraphwidth}{\widthof{\mytextformat#1}}\originalepigraph{#1}{#2}}

\begin{document}

\epigraph{All models are wrong, but some are useful.}{George E. P. Box}

\end{document}

output of code

Alan Munn
  • 218,180
6

At the preamble, use this to define a command \epiline to use as \hline but with other sizes.

\newlength\epirule%
\newcommand\epiline{%
\noalign{\global\epirule\arrayrulewidth\global\arrayrulewidth 1pt}\hline%
\noalign{\global\arrayrulewidth\epirule}%
}

Here, the command \epigraph with two arguments (you don't need the package here).

\newcommand\epigraph[2]{%
\hfill\begin{tabular}{@{}r@{}}
{\small\textit{#1}}\\[.5em] \epiline%
{\small\textsc{#2}}
\end{tabular}
}

Then you can use it as

\epigraph{All models are wrong, but some are useful}{George E.\ P.\ Box}

enter image description here

Sigur
  • 37,330