Selective and bunched entries to list of figures
Since you are already manually outputting the \contentsline
instruction, you can automate the process a bit. Add this to the preamble:
\makeatletter
\def\beginfigrange#1{%initiates the start of the figure range
\label{#1}
\edef\dummy{\noexpand\figrangestartpage{\thepage}}
\expandafter\gdef\dummy
\gdef\figrangestartlbl{#1}}
\def\endfigrange#1#2{%ends the figure range and writes the \contentsline to the aux
\label{#1}
\@ifundefined{r@#1}{}{%
\edef\dummylabel{\figrangestartlbl}
\immediate\write\@auxout{\noexpand\@writefile {lof}{\noexpand\contentsline{figure}{\noexpand\numberline {\noexpand\ref{\dummylabel}--\ref{#1}}\ignorespaces #2}{\figrangestartpage --\thepage}}}}
\gdef\figrangestartpage{\relax}
\gdef\figrangestartlbl{\relax}}
\renewcommand\l@figure{\@dottedtocline{1}{1.5em}{5em}}
\makeatother
Then, in place of \label{fig:XX}
in the figure environment, call \beginfigrange{fig:XX}
in the first figure environment and \endfigrange{fig:YY}{List of Figures description}
in the last one.
For example:
\begin{center}
\captionof{figure}[]{Princess 1}
%\label{fig:fifth}
\beginfigrange{fig:fifth}
\end{center}
and
\begin{center}
\captionof{figure}[]{Princess 2}
%\label{fig:sixth}
\endfigrange{fig:sixth}{Various princesses page numbers wrong want a range}
\end{center}
from your MWE.
The \l@figure
macro is used to format the lines in the List of Figures, hence its redefinition.
Edit:
The \write
for \label
isn't called immediately, so an error will result on the first run when \endfigrange
is called. Subsequent runs should be fine. The \@ifundefined{r@#1}{}{%
line prevents this initial error.
I don't like hiding the \label{fig:XX}
, which my first answer does. An alternative that follows convention is to use \thefigure
to pull the requisite figure identifier, as opposed to using the label key. This allows the first macro to serve as a "flag" and removes the potential reference error in the second. Additionally, I've incorporated a check for hyperref
so that, if it is loaded, the List of Figures entry will link to the first figure in the range.
\documentclass[a4paper]{book}
\usepackage{caption}
\usepackage{hyperref}
\makeatletter
\def\beginfigrange{%initiates the start of the figure range
\edef\dummy{\noexpand\figrangestartpage{\thepage}}
\expandafter\gdef\dummy
\edef\dummy{\noexpand\figrangestartlbl{\thefigure}}
\expandafter\gdef\dummy
%added to use the same reference key as hyperref; will work for \caption, \captionof, and with the hypertexnames=false option
\expandafter\ifx\expandafter\relax\usinghyperref\relax%saves the current hyperlink if hyperref is used
\gdef\hyperapp{\relax}
\else
\edef\dummy{\expandafter\noexpand\expandafter\hyperapp{\@currentHref}}
\expandafter\gdef\dummy
\fi}
\def\endfigrange#1{%ends the figure range and writes the \contentsline to the aux
\edef\dummylabel{\figrangestartlbl}
\edef\dummy{\thefigure}
\immediate\write\@auxout{\noexpand\@writefile{lof}{\noexpand\contentsline{figure}{\noexpand\numberline {\dummylabel--\dummy}{\ignorespaces #1}}{\figrangestartpage --\thepage}{\hyperapp}}}
\gdef\figrangestartpage{\relax}
\gdef\figrangestartlbl{\relax}
\gdef\hyperapp{\relax}}
\renewcommand\l@figure{\@dottedtocline{1}{1.5em}{5em}}
\AtBeginDocument{%Defined such that \usinghyperref = \relax if not using hyperref
\@ifpackageloaded{hyperref}
{\gdef\usinghyperref{true}}
{\gdef\usinghyperref{\relax}}}
\makeatother
Use:
\begin{center}
\captionof{figure}[]{Princess 1}
\label{fig:fifth}
\beginfigrange
\end{center}
and:
\begin{center}
\captionof{figure}[]{Princess 2}
\label{fig:sixth}
\endfigrange{Various princesses page numbers wrong want a range}
\end{center}
Variant:
Added to the preamble (with \usepackage{keyval}
),
\makeatletter
\AtBeginDocument{%
%keyvalues for the new second option of caption and captionof
\define@key{runfig}{beginrange}[true]{\def\runfig@beginrange{#1}}
\define@key{runfig}{endrange}[Figure range LOF entry]{\def\runfig@endrange{#1}}
\def\runfigdefaults{\setkeys{runfig}{beginrange={\relax}, endrange={\relax}}}
\gdef\figrangestartlbl{\relax}%use the label as a flag to indicate if the current figure is within a running fig; if so, it will not be in the list of figures.
%redefine \caption and \captionof
\let\@oldcaption=\caption
\let\@oldcaptionof=\captionof
\def\caption{\@ifstar{\@newcapstar}{\@newcapnostar}}
\def\@newcapnostar{\@ifnextchar[{\@newcapnostaropa}{\@newcapnostarnoop}}
\def\@newcapnostaropa[#1]{\@ifnextchar[{\@newcapnostaropaa[#1]}{\@newcapnostaropab[#1]}}
\def\@newcapnostaropab[#1]#2{\@newcapnostaropaa[#1][]{#2}}
\def\@newcapnostarnoop#1{\@newcapnostaropaa[][]{#1}}
\def\@newcapnostaropaa[#1][#2]#3{%
\runfigdefaults
\setkeys{runfig}{#2}
\expandafter\ifx\expandafter\relax\runfig@beginrange\relax%not beginfigrange
\expandafter\ifx\expandafter\relax\runfig@endrange\relax%not endfigrange
\expandafter\if\expandafter\relax\figrangestartlbl\relax%not running...default caption behavior
\@oldcaption[#1]{#3}
\else%is running, exclude from LOF
\@oldcaption[]{#3}
\fi
\else%is endfigrange
\@oldcaption[]{#3}
\endfigrange{\runfig@endrange}
\fi
\else%is beginfigrange
\@oldcaption[]{#3}
\beginfigrange
\fi
}
\def\@newcapstar{\@oldcaption}%the second option is not enabled for the starred variant
%redefine captionof
\def\captionof{\@ifstar{\@newcapofstar}{\@newcapofnostar}}
\def\@newcapofnostar#1{\@ifnextchar[{\@newcapofnostaropa#1}{\@newcapofnostarnoop#1}}
\def\@newcapofnostaropa#1[#2]{\@ifnextchar[{\@newcapofnostaropaa#1[#2]}{\@newcapofnostaropab#1[#2]}}
\def\@newcapofnostaropab#1[#2]#3{\@newcapofnostaropaa#1[#2][]#3}
\def\@newcapofnostarnoop#1#2{\@newcapofnostaropaa#1[][]#2}
\def\@newcapofnostaropaa#1[#2][#3]#4{%
\runfigdefaults
\setkeys{runfig}{#3}
\expandafter\ifx\expandafter\relax\runfig@beginrange\relax%not beginfigrange
\expandafter\ifx\expandafter\relax\runfig@endrange\relax%not endfigrange
\expandafter\if\expandafter\relax\figrangestartlbl\relax%not running...default caption behavior
\@oldcaptionof{#1}[#2]{#4}
\else%is running, exclude from LOF
\@oldcaptionof{#1}[]{#4}
\fi
\else%is endfigrange
{\@oldcaptionof{#1}[]{#4}}%\captionof calls caption, which resets keys (hence group)
\endfigrange{\runfig@endrange}
\fi
\else%is beginfigrange
\@oldcaptionof{#1}[]{#4}
\beginfigrange
\fi
}
\def\@newcapstar{\@oldcaptionof}%the second option is not enabled for the starred variant
}
\makeatother
This redefines \caption
and \captionof
to have a second optional parameter, which controls the running figure range. The advantage here is that all of the captions would be defined normally, then the second parameter could be added without having to redefine the captions of the figures between them. Use is demonstrated below:
\begin{center}
\captionof{figure}[][beginrange]{Princess 1}
\label{fig:fifth}
%\beginfigrange
\end{center}
and
\begin{center}
\captionof{figure}[][endrange=Various princess page numbers wrong want a range]{Princess 2}
\label{fig:sixth}
%\endfigrange{Various princesses page numbers wrong want a range}
\end{center}
Here is a proof-of-concept that doesn't require much fiddling around; you construct the "combined LoF caption entry" yourself using \ref
s and \pageref
s:
\documentclass{article}
\usepackage{lipsum}
\usepackage{caption,graphicx}
\usepackage{tocloft}
\cftsetpnumwidth{3em}
\begin{document}
\sloppy% Just for this example
\listoffigures
\section{Document body}
% Some image within the document body
\begin{figure}[ht]
\centering
\includegraphics[width=1cm]{example-image}
\caption{Example image}
\end{figure}
\appendix
\section{Appendix}
\captionsetup[figure]{list=no}
% First image in Appendix
\begin{figure}[ht]
\centering
\includegraphics[width=1cm]{example-image}
\caption{First image in Appendix}
\label{fig:first-image}
\end{figure}
\lipsum[1-50]% A whole bunch more images
\lipsum[1-50]% A whole bunch more images
\lipsum[1-50]% A whole bunch more images
\addtocounter{figure}{50}% Just for this example
% Last image in Appendix
\begin{figure}[ht]
\centering
\includegraphics[width=1cm]{example-image}
\caption{Last image in Appendix}
\label{fig:last-image}
\end{figure}
% Insert combined LoF entry
\addtocontents{lof}{%
\protect\contentsline{figure}
{\protect\numberline{\protect\ref{fig:first-image}--\protect\ref{fig:last-image}}% Image range
A collection of images}% Collection title
{\protect\pageref{fig:first-image}--\protect\pageref{fig:last-image}}% Page range
{}% ...for hyperref
}
\end{document}
If the contents entries need to be indented naturally due to a large figure range, then simply drop the \protect\numberline
entry and insert an appropriate space:
% Insert combined LoF entry
\addtocontents{lof}{%
\protect\contentsline{figure}
{\protect\ref{fig:first-image}--\protect\ref{fig:last-image} % Image range
A collection of images}% Collection title
{\protect\pageref{fig:first-image}--\protect\pageref{fig:last-image}}% Page range
{}% ...for hyperref
}
The above is compatible with hyperref
.