7

This is a follow up to "Include chapters in List of Figures with titletoc?". There appears to be a problem with the original solution when a float is placed at the top of the page following a new part/chapter. In the LoF, the figure caption is then above the inserted part/chapter title (see screenshot). If we change the float position to b or anything else, it works fine.

The code below is adapted to report class, but I've checked and exists in book/report/article and its KOMA equivalents.

\documentclass{scrreprt}

\usepackage{lipsum}

\usepackage{etoolbox}
\makeatletter
\def\thisparttitle{}\def\thispartnumber{}
\newtoggle{noFigs}

\apptocmd{\@part}%
  {\gdef\thisparttitle{#1}\gdef\thispartnumber{\thepart}%
    \global\toggletrue{noFigs}}{}{}

\AtBeginDocument{%
  \AtBeginEnvironment{figure}{%
    \iftoggle{noFigs}{
      \addtocontents{lof}{\protect\contentsline {part}%
        {\protect\numberline {\thispartnumber} {\thisparttitle}}{}{} }
      \global\togglefalse{noFigs}
    }{}
  }%
}

\makeatother

\begin{document}

\listoffigures

\part{Part 1}

\chapter{Hallo}

\lipsum

\section{Hallo}

\begin{figure}[t] % change placement to cbt and it works
\caption{Part 1 Fig}
  Test
\end{figure}


\end{document}

enter image description here


Edit

The suggested solution from Heiko below has a problem when several figures/tables are in different parts. For example:

\begin{document}

\listoftables\listoffigures

\part{Part 1}
\begin{table}\caption{Part 1 Tab}\end{table}

\part{Part 2}
\begin{table}\caption{Part 1 Tab}\end{table}
\begin{figure}\caption{Part 1 Fig}\end{figure}

\end{document}

enter image description here

7
+300

The additional part contents line (in the list of figures) is added at the begin of macro \figure (\begin{figure}). There the float has not yet started and the write directive for the part line goes at the place of the figure in the source.

The float object will be created later in \@xfloat. \caption will then write its contents line inside the float object. But the float object can float to a location before the source code location, in your case with option t. Then the two contents lines get out of order.

This can be fixed by moving the part contents line inside the float box.

Instead of the very begin of the float environment, still outside the float box, the following example hooks into \@floatboxreset, which is automatically called at the begin of the float box. LaTeX remembers the type of the float object in \@captype and macro \ext@<captype> (<captype> ∈ {figure, table, ...}) contains the list type (\ext@figure -> lof). This way, also the other float types are supported automatically, if they follow the LaTeX conventions. For example, new floats, defined by package float will work.

A new float type only needs a new toggle and the toggle to be reset at the start of a new part. This is done by macro \AddFloatToggle in the example.

\documentclass{scrreprt}

\usepackage{etoolbox}

\makeatletter
% Initialize variables
\newcommand*{\ResetFloatToggles}{}% toggle reset list for \part
\newcommand*{\thisparttitle}{}
\newcommand*{\thispartnumber}{}

\newcommand*{\AddFloatToggle}[1]{%
  \newtoggle{no#1s}%
  \apptocmd{\ResetFloatToggles}{%
    \global\toggletrue{no#1s}%
  }{}{}%
}   
% Set variables and reset float toggles at the start of \part
\apptocmd{\@part}{%
  % Remember part title and part number
  \gdef\thisparttitle{#1}%
  \gdef\thispartnumber{\thepart}%
  \ResetFloatToggles
}{}{}
% Emit \addcontentsline at the begin of the float box
\apptocmd{\@floatboxreset}{%
  % Test, if toggle exists for this float type.
  % Since there isn't an official command for testing
  % toggle existence, the internal code for testing
  % is used, see the definition of \newtoggle.
  \ifcsdef{etb@tgl@no\@captype s}{%
    \iftoggle{no\@captype s}{%
      % \@captype is the type of float, e.g. "figure", "table", "program"
      % \ext@... (\ext@figure, \ext@table, \ext@program)
      % contains the type/extension for the list of the float type, e.g.
      % "lof", "lot", "lop".
      \addcontentsline{\csname ext@\@captype\endcsname}{part}{%
        \protect\numberline{\thispartnumber} {\thisparttitle}%
      }%
      \global\togglefalse{no\@captype s}%
    }{}%
  }{%
    % unsupported float type
    \typeout{Warning: there is no toggle for float type \@captype!}%
  }%
}{}{}
\makeatother

\usepackage{float}
\newfloat{program}{tbp}{lop}[chapter]

\AddFloatToggle{figure}
\AddFloatToggle{table}
\AddFloatToggle{program}

\begin{document}

\listoftables
\listoffigures
\listof{program}{List of Programs}

\part{Part 1}
\begin{table}\caption{Part 1 Tab}\end{table}
\begin{program}\caption{Part 1 Program}\end{program}

\part{Part 2}
\begin{table}\caption{Part 2 Tab}\end{table}
\begin{figure}\caption{Part 2 Fig}\end{figure}

\end{document}

List of Tables

List of Figures

List of Programs

  • Thanks! Is there a reason for \addcontentsline{\csname ext@\@captype\endcsname} ... instead of \addtocontents{lof}...? – Jörg Nov 15 '14 at 15:23
  • 1
    @Jörg \@xfloat is called for all float objects. \@captype expands to figure inside figure floats and \ext@figure to lof. In case of tables, the entry would be written to lot. – Heiko Oberdiek Nov 15 '14 at 16:13
  • There appears to be a problem with several tables/figures in different parts. I've added an example above. – Jörg Nov 15 '14 at 17:26
  • @Jörg The code to support different float types was incomplete. Fixed now. – Heiko Oberdiek Nov 15 '14 at 18:50
  • Very nice! Could you perhaps add a sentence about the float- check (\ifcsdef {etb@tgl@no\@captype s})? Would (in principle) custom floats from float package be supported? What would "unsupported float type" be? – Jörg Nov 15 '14 at 19:09
3

Apparently LaTeX doesn't realize it entered into a part, until it encounters something else inside the part.

EDIT

Here is an automated procedure. It is about modifying command \@caption. Now it stores correctly the caption and then the environment figure applies it to the List Of Figures at the end of the environment:

\long\def\@caption#1[#2]#3{%
  \par
  \gdef\my@caption{#2}
  \begingroup
    \@parboxrestore
    \if@minipage
      \@setminipage
    \fi
    \normalsize
    \@makecaption{\csname fnum@#1\endcsname}{\ignorespaces #3}\par
  \endgroup}

\renewenvironment{figure}%
               {\@float{figure}}%
               {\end@float
               \addcontentsline{lof}{figure}%
                   {\protect\numberline{\thefigure}{\my@caption}}%
               }%
\renewenvironment{figure*}%
               {\@dblfloat{figure}}%
               {\end@dblfloat
               \addcontentsline{lof}{figure}%
                   {\protect\numberline{\thefigure}{\my@caption}}%
               }%

Then your document will become:

\documentclass{scrreprt}

\usepackage{lipsum}

\usepackage{etoolbox}
\makeatletter
\def\thisparttitle{}\def\thispartnumber{}
\newtoggle{noFigs}

\apptocmd{\@part}%
  {\gdef\thisparttitle{#1}\gdef\thispartnumber{\thepart}%
    \global\toggletrue{noFigs}}{}{}

\AtBeginDocument{%
  \AtBeginEnvironment{figure}{%
    \iftoggle{noFigs}{
      \addtocontents{lof}{\protect\contentsline {part}%
        {\protect\numberline {\thispartnumber} {\thisparttitle}}{}{} }
      \global\togglefalse{noFigs}
    }{}
  }%
}

\long\def\@caption#1[#2]#3{%
  \par
  \gdef\my@caption{#2}
  \begingroup
    \@parboxrestore
    \if@minipage
      \@setminipage
    \fi
    \normalsize
    \@makecaption{\csname fnum@#1\endcsname}{\ignorespaces #3}\par
  \endgroup}

\renewenvironment{figure}%
               {\@float{figure}}%
               {\end@float
               \addcontentsline{lof}{figure}%
                   {\protect\numberline{\thefigure}{\my@caption}}%
               }%
\renewenvironment{figure*}%
               {\@dblfloat{figure}}%
               {\end@dblfloat
               \addcontentsline{lof}{figure}%
                   {\protect\numberline{\thefigure}{\my@caption}}%
               }%

\makeatother

\begin{document}

\listoffigures

\part{Part 1}

\chapter{Hallo}

\lipsum

\section{Hallo}

\begin{figure}[t]
\caption{First figure}
  Test
\end{figure}

\begin{figure}[b]
\caption{Second figure}
  Test
\end{figure}

\end{document}

part list figures contents line

Now you are able to assign any positioning argument to your figure environment.


Here is another way to resolve your problem:

\documentclass{scrreprt}

\usepackage{lipsum}

\usepackage{etoolbox}
\makeatletter
\def\thisparttitle{}\def\thispartnumber{}
\newtoggle{noFigs}

\apptocmd{\@part}%
  {\gdef\thisparttitle{#1}\gdef\thispartnumber{\thepart}%
    \global\toggletrue{noFigs}}{}{}

\AtBeginDocument{%
  \AtBeginEnvironment{figure}{%
    \iftoggle{noFigs}{
      \addtocontents{lof}{\protect\contentsline {part}%
        {\protect\numberline {\thispartnumber} {\thisparttitle}}{}{} }
      \global\togglefalse{noFigs}
    }{}
  }%
}

\makeatother

\begin{document}

\listoffigures

\part{Part 1}

\chapter{Hallo}

\lipsum

\section{Hallo}

\let\aclt\addcontentsline
\renewcommand*{\addcontentsline}[3]{}
\begin{figure}[t] % change placement to cbt and it works
\caption{Part 1 Fig}
  Test
\end{figure}
\let\addcontentsline\aclt

\addcontentsline{lof}{figure}%
    {\protect\numberline{\thefigure}{Part 1 Fig}}%

\end{document}

I just delayed a little bit the execution of \addcontentsline, a command which is part of \caption and adds the entry line to the List Of Figures.

ANOTHER EDIT

This is achieved by suppressing \addcontentsline using \renewcommand*, after storing a copy of the suppressed command into \aclt. After the figure environment \addcontentsline is restored to give the previous output, and then it's executed with parameters matching the wanted output. Note that the third parameter contains exactly \caption's argument.

  • So this solution requires adding a manual delay of \addcontentsline and the figure that causes the problem? – Jörg Nov 15 '14 at 12:34
  • I edited to explain the process – RicoRally Nov 15 '14 at 12:39
  • That's not what I mean: the solution does not provide a general fix (i.e. in the preamble) for all potential figures that may cause trouble. I have to adjust the \addcontentsline for a specific figure. – Jörg Nov 15 '14 at 12:46
  • I edited to add that – RicoRally Nov 15 '14 at 12:50
  • Yes, I wondered about patching the environment. But is it a good idea to patch \addcontentsline for universally? – Jörg Nov 15 '14 at 12:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.